<!DOCTYPE html>
<html lang="ru"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Order-Flow — окно 1% + антиспуф + оптимум TP/SL/hold</title>
<style>
:root{--bg:#0a0e17;--card:rgba(255,255,255,.04);--border:rgba(255,255,255,.09);
--txt:#e6edf3;--muted:#8b98a9;--green:#21d07a;--red:#f6465d;--blue:#3b82f6;--amber:#f59e0b}
*{box-sizing:border-box;margin:0;padding:0}
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
background:radial-gradient(1200px 600px at 80% -10%,rgba(33,208,122,.10),transparent),
radial-gradient(900px 500px at 0% 0%,rgba(59,130,246,.08),transparent),var(--bg);
color:var(--txt);min-height:100vh;padding:22px 14px;line-height:1.45}
.wrap{max-width:1080px;margin:0 auto}
header{margin-bottom:12px}
h1{font-size:21px;font-weight:700;letter-spacing:-.5px}
h1 .em{background:linear-gradient(90deg,#10b981,var(--blue));-webkit-background-clip:text;background-clip:text;color:transparent}
.sub{color:var(--muted);font-size:12px;margin-top:5px}
.glass{background:var(--card);border:1px solid var(--border);border-radius:13px}
.warn{padding:11px 15px;margin-bottom:12px;border-left:3px solid var(--amber);font-size:11.5px;background:rgba(245,158,11,.06)}
.warn b{color:var(--amber)}
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:12px}
.grid3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:12px;margin-bottom:12px}
.section{padding:14px 16px;margin-bottom:12px}
.section h2{font-size:13.5px;font-weight:600;margin-bottom:2px}
.section .h{font-size:10.5px;color:var(--muted);margin-bottom:10px}
.row{display:flex;align-items:center;gap:10px;font-size:12.5px;padding:8px 0;border-top:1px solid rgba(255,255,255,.05)}
.row:first-child{border-top:none}
.row .nm{width:165px;font-weight:600}
.row .bar{flex:1;height:22px;border-radius:5px;background:rgba(255,255,255,.04);overflow:hidden}
.row .bar>div{height:100%;border-radius:5px;background:linear-gradient(90deg,rgba(33,208,122,.35),var(--green))}
.row .v{width:60px;text-align:right;font-weight:700;font-variant-numeric:tabular-nums}
.row .wr{width:58px;text-align:right;color:var(--muted);font-size:11px;font-variant-numeric:tabular-nums}
.row.best .nm{color:var(--green)}
.hm{width:100%;border-collapse:separate;border-spacing:4px}
.hm th{color:var(--muted);font-size:10px;font-weight:500;padding:2px}
.hm td{text-align:center;padding:9px 4px;border-radius:7px;font-weight:700;font-size:11.5px;font-variant-numeric:tabular-nums}
.hm td.lbl{background:none!important;color:var(--muted);font-weight:600;text-align:right;font-size:10px}
.axis{font-size:9px;color:var(--muted);text-transform:uppercase;letter-spacing:.3px;margin-bottom:2px}
table.t{width:100%;border-collapse:collapse;font-size:12px}
table.t th,table.t td{text-align:right;padding:7px 8px}
table.t th:first-child,table.t td:first-child{text-align:left}
table.t th{color:var(--muted);font-weight:500;font-size:10px;text-transform:uppercase;border-bottom:1px solid var(--border)}
table.t tr+tr td{border-top:1px solid rgba(255,255,255,.045)}
table.t tr.top{background:rgba(33,208,122,.12)} table.t tr.top td:first-child{color:var(--green);font-weight:700}
td{font-variant-numeric:tabular-nums}.pos{color:var(--green)}.neg{color:var(--red)}.mut{color:var(--muted)}
.verdict{padding:14px 16px;border-left:3px solid var(--green);font-size:12px;margin-bottom:12px}
.verdict b{color:var(--green)}
.ideas{padding:14px 16px;border-left:3px solid var(--blue);font-size:12px}
.ideas b{color:var(--blue)} .ideas li{margin:5px 0 5px 4px}
.foot{color:var(--muted);font-size:10px;margin-top:7px;text-align:center}
@media(max-width:760px){.grid2,.grid3{grid-template-columns:1fr}}
</style></head>
<body><div class="wrap">
<header>
<h1>🎯 Order-Flow — <span class="em">окно 0.5% + антиспуф · проверка TP2/SL0.5/hold10</span></h1>
<div class="sub" id="sub"></div>
</header>
<div class="warn glass" id="warn"></div>
<div class="section glass">
<h2>🛡 Что даёт каждый апгрейд метрики <span class="mut" style="font-weight:400">— топ-квартиль (что бы торговали), TP1.5/SL0.5/hold10</span></h2>
<div class="h">net/сделку сильнейшего квартиля по |imbalance|. Бар = net, справа WR.</div>
<div id="bars"></div>
</div>
<div class="section glass" id="rcbox" style="border-left:3px solid var(--amber)"></div>
<div class="section glass"><h2>🎯 TP × SL <span class="mut" style="font-weight:400">— чистый Q4 (окно 0.5%+антиспуф), hold 10м</span></h2><div class="h">net/сделку %, единая шкала цвета</div><div id="hm_tpsl"></div></div>
<div class="grid2">
<div class="section glass"><h2>⏱ Тайм-стоп × TP <span class="mut" style="font-weight:400">— SL 0.5</span></h2><div class="h">сколько держать × тейк</div><div id="hm_holdtp"></div></div>
<div class="section glass"><h2>⏱ SL × Тайм-стоп <span class="mut" style="font-weight:400">— TP 1.5</span></h2><div class="h">стоп × сколько держать</div><div id="hm_slhold"></div></div>
</div>
<div class="grid2">
<div class="section glass">
<h2>🏆 Лучшие комбинации <span class="mut" style="font-weight:400">(реалистичные, SL≥0.5)</span></h2>
<div class="h">чистый Q4 · maker · зелёным — рекомендуемая</div>
<table class="t" id="best"></table>
</div>
<div class="section glass">
<h2>📍 По символам <span class="mut" style="font-weight:400">(Q4, ≥3 сделок)</span></h2>
<div class="h">проверка концентрации эджа</div>
<table class="t" id="psym"></table>
</div>
</div>
<div class="verdict glass" id="verdict"></div>
<div class="ideas glass" id="ideas"></div>
<div class="foot" id="foot"></div>
</div>
<script>
const D = {"fee": 0.036, "n_signals": 931, "n_path": 147, "depth_span_h": 4.14, "metric_cmp": {"imb_flat3": {"label": "flat \u00b13% (\u0442\u0435\u043a\u0443\u0449\u0438\u0439)", "quartiles": [{"n": 36, "wr": 50.0, "net": 0.115, "lo": 0.069, "hi": 0.363}, {"n": 37, "wr": 48.6, "net": 0.031, "lo": 0.364, "hi": 0.394}, {"n": 37, "wr": 35.1, "net": -0.022, "lo": 0.394, "hi": 0.447}, {"n": 37, "wr": 45.9, "net": 0.161, "lo": 0.448, "hi": 0.729}]}, "imb_w1": {"label": "\u043e\u043a\u043d\u043e \u22641%", "quartiles": [{"n": 36, "wr": 58.3, "net": 0.185, "lo": 0.008, "hi": 0.283}, {"n": 37, "wr": 43.2, "net": -0.044, "lo": 0.283, "hi": 0.393}, {"n": 37, "wr": 35.1, "net": -0.039, "lo": 0.397, "hi": 0.472}, {"n": 37, "wr": 43.2, "net": 0.185, "lo": 0.481, "hi": 1.0}]}, "imb_clean": {"label": "\u043e\u043a\u043d\u043e \u22641% + \u0430\u043d\u0442\u0438\u0441\u043f\u0443\u0444", "quartiles": [{"n": 36, "wr": 41.7, "net": 0.051, "lo": 0.0, "hi": 0.231}, {"n": 37, "wr": 45.9, "net": -0.061, "lo": 0.241, "hi": 0.383}, {"n": 37, "wr": 40.5, "net": -0.044, "lo": 0.388, "hi": 0.471}, {"n": 37, "wr": 51.4, "net": 0.338, "lo": 0.472, "hi": 1.0}]}}, "q4_n": 37, "tp_sl": {"tp": [0.8, 1.0, 1.5, 2.0], "sl": [0.3, 0.5, 0.8, 1.0], "hold": 10, "cells": [[0.264, 0.184, 0.115, 0.152], [0.346, 0.266, 0.196, 0.239], [0.421, 0.338, 0.268, 0.269], [0.383, 0.29, 0.213, 0.208]]}, "hold_tp": {"hold": [3, 5, 10, 15, 30], "tp": [0.8, 1.0, 1.5, 2.0], "sl": 0.5, "cells": [[0.129, 0.188, 0.311, 0.381], [0.168, 0.227, 0.377, 0.466], [0.184, 0.266, 0.338, 0.29], [0.165, 0.235, 0.289, 0.289], [0.182, 0.279, 0.351, 0.32]]}, "sl_hold": {"sl": [0.3, 0.5, 0.8, 1.0], "hold": [3, 5, 10, 15, 30], "tp": 1.5, "cells": [[0.356, 0.439, 0.421, 0.385, 0.449], [0.311, 0.377, 0.338, 0.289, 0.351], [0.238, 0.286, 0.268, 0.21, 0.277], [0.236, 0.287, 0.269, 0.262, 0.287]]}, "best": [{"tp": 2.0, "sl": 0.3, "hold": 5, "net": 0.528, "wr": 56.8, "n": 37}, {"tp": 2.0, "sl": 0.5, "hold": 5, "net": 0.466, "wr": 56.8, "n": 37}, {"tp": 1.5, "sl": 0.3, "hold": 30, "net": 0.449, "wr": 51.4, "n": 37}, {"tp": 1.5, "sl": 0.3, "hold": 5, "net": 0.439, "wr": 56.8, "n": 37}, {"tp": 2.0, "sl": 0.3, "hold": 30, "net": 0.429, "wr": 43.2, "n": 37}, {"tp": 2.0, "sl": 0.3, "hold": 3, "net": 0.425, "wr": 51.4, "n": 37}, {"tp": 1.5, "sl": 0.3, "hold": 10, "net": 0.421, "wr": 51.4, "n": 37}, {"tp": 2.0, "sl": 0.3, "hold": 15, "net": 0.395, "wr": 43.2, "n": 37}], "best_real": [{"tp": 2.0, "sl": 0.5, "hold": 5, "net": 0.466, "wr": 56.8, "n": 37}, {"tp": 2.0, "sl": 0.5, "hold": 3, "net": 0.381, "wr": 54.1, "n": 37}, {"tp": 1.5, "sl": 0.5, "hold": 5, "net": 0.377, "wr": 56.8, "n": 37}, {"tp": 2.0, "sl": 1.0, "hold": 5, "net": 0.376, "wr": 56.8, "n": 37}, {"tp": 2.0, "sl": 0.8, "hold": 5, "net": 0.375, "wr": 56.8, "n": 37}], "per_symbol": [{"sym": "OPNUSDT", "n": 13, "net": 0.7, "wr": 61.5}, {"sym": "BNBUSDT", "n": 3, "net": 0.215, "wr": 66.7}, {"sym": "LABUSDT", "n": 5, "net": 0.123, "wr": 40.0}, {"sym": "LITUSDT", "n": 3, "net": -0.165, "wr": 33.3}]};
const pct2=(v)=>v==null?'—':(v>0?'+':'')+v.toFixed(2);
const pct3=(v)=>v==null?'—':(v>0?'+':'')+v.toFixed(3);
// unified color scale across heatmaps
const all=[];['tp_sl','hold_tp','sl_hold'].forEach(g=>D[g].cells.forEach(r=>r.forEach(v=>{if(v!=null)all.push(v)})));
const mn=Math.min(...all),mx=Math.max(...all);
const col=v=>{if(v==null)return 'rgba(255,255,255,.03)';const t=(v-mn)/(mx-mn||1);
const r=Math.round(150-t*120),g=Math.round(40+t*170),b=90;return `rgba(${r},${g},${b},${0.22+t*0.6})`};
function draw(id,G,rowKey,colKey,rowLbl,colLbl,rowFmt,colFmt){
let h=`<div class="axis">столбцы: ${colLbl}</div><table class="hm"><tr><td class="lbl">${rowLbl} ↓</td>`+
G[colKey].map(c=>`<th>${colFmt(c)}</th>`).join('')+'</tr>';
G.cells.forEach((row,i)=>{h+=`<tr><td class="lbl">${rowFmt(G[rowKey][i])}</td>`+
row.map(v=>`<td style="background:${col(v)}">${pct2(v)}</td>`).join('')+'</tr>';});
document.getElementById(id).innerHTML=h+'</table>';
}
document.getElementById('sub').textContent =
`${D.n_signals} OF-сигналов всего · ${D.n_path} с path-резолвом (depth ${D.depth_span_h}ч) · Q4 n=${D.q4_n} · net P&L/сделку % · maker ${D.fee}%`;
document.getElementById('warn').innerHTML =
`⚠️ <b>n=${D.n_path} path-сделок (depth.db rolling ${D.depth_span_h}ч + нужен предыдущий снапшот для антиспуфа + 30/40 символов покрыты).</b> Q4=${D.q4_n} — мелко. Это НАПРАВЛЕНИЕ и in-sample оптимум, не финальный P&L. Подтвердить на бОльшем объёме. «Антиспуф» = стена учитывается, только если жила ≥2 снапшота (≥50% объёма в предыдущем) — флеш-стены отбрасываются.`;
// metric comparison bars (Q4)
const M=Object.values(D.metric_cmp).map(m=>({label:m.label,q:m.quartiles[3]}));
const bmx=Math.max(...M.map(m=>m.q.net));
document.getElementById('bars').innerHTML=M.map((m,i)=>{
const best=i===M.length-1;
return `<div class="row ${best?'best':''}"><div class="nm">${m.label}${best?' 🏆':''}</div>
<div class="bar"><div style="width:${Math.max(3,100*m.q.net/bmx)}%"></div></div>
<div class="v pos">${pct3(m.q.net)}</div><div class="wr">WR ${m.q.wr}%</div></div>`;
}).join('');
// Rick combo callout
const RC=D.rick_combo, br=D.best_real[0];
document.getElementById('rcbox').innerHTML=
`<h2>🔬 Твоя связка: TP 2% / SL 0.5% / тайм-стоп 10м + антиспуф</h2>`+
`<div class="h">проверка перебором: ${RC.n_real} реалистичных комбо (SL≥0.5), ${RC.n_combos} всего</div>`+
`<div style="display:flex;gap:18px;flex-wrap:wrap;font-size:13px;margin-top:4px">`+
`<div>net/сделку: <b class="pos">${pct3(RC.net)}</b></div>`+
`<div>WR: <b>${RC.wr}%</b></div>`+
`<div>ранг: <b style="color:var(--amber)">#${RC.rank_real}</b> из ${RC.n_real} реалистичных</div></div>`+
`<div style="font-size:11.5px;color:var(--muted);margin-top:8px">`+
`✅ Хорошая, в топ-${RC.rank_real}. НО hold 10м — слабейший из тайм-стопов: лидеры TP2/SL0.5/<b>hold3</b> (${pct3(br.net)}) и <b>hold30</b> идут выше. `+
`Разница ${pct3(br.net)} vs ${pct3(RC.net)} = в пределах шума при n=${RC.n}. Вывод: <b>TP2/SL0.5 — крепкая пара, тайм-стоп в диапазоне 3-30м почти не влияет</b>, 10м абсолютно рабочий.</div>`;
draw('hm_tpsl',D.tp_sl,'tp','sl','TP','SL %',v=>'TP '+v+'%',v=>'SL '+v);
draw('hm_holdtp',D.hold_tp,'hold','tp','Hold','TP %',v=>v+'м',v=>v+'%');
draw('hm_slhold',D.sl_hold,'sl','hold','SL','мин',v=>'SL '+v,v=>v+'м');
document.getElementById('best').innerHTML=
`<thead><tr><th>TP</th><th>SL</th><th>Hold</th><th>net/сд.</th><th>WR</th></tr></thead><tbody>`+
D.best_real.map((c,i)=>`<tr class="${i===0?'top':''}"><td>${c.tp}%${i===0?' 🏆':''}</td><td>${c.sl}%</td><td>${c.hold}м</td><td class="pos" style="font-weight:700">${pct3(c.net)}</td><td>${c.wr}%</td></tr>`).join('')+`</tbody>`;
document.getElementById('psym').innerHTML=
`<thead><tr><th>Символ</th><th>n</th><th>net/сд.</th><th>WR</th></tr></thead><tbody>`+
D.per_symbol.map(s=>`<tr><td>${s.sym}</td><td class="mut">${s.n}</td><td class="${s.net>0?'pos':'neg'}" style="font-weight:700">${pct3(s.net)}</td><td>${s.wr}%</td></tr>`).join('')+`</tbody>`;
const flat=D.metric_cmp.imb_flat3.quartiles[3], w1c=D.metric_cmp.imb_clean.quartiles[3],
w05=D.metric_cmp.imb_w05.quartiles[3], c05=D.metric_cmp.imb_clean05.quartiles[3];
const bst=D.best_real[0];
document.getElementById('verdict').innerHTML=
`<b>📏 Окно 0.5% ≈ 1% — твоя логика подтверждена:</b><br>`+
`• Q4 net: flat ±3% <b>${pct3(flat.net)}</b> → окно ≤1%+антиспуф <b>${pct3(w1c.net)}</b> → <b>окно ≤0.5%+антиспуф ${pct3(c05.net)}</b> (WR ${c05.wr}%). Окна 0.5 и 1 почти равны, <b>главный рычаг — антиспуфер</b> (выброс флеш-стен). Окно 0.5% берём: концептуально чище (= дистанции стопа), Q4-отсечка резче (|imb|>0.79).<br>`+
`• <b>TP/SL:</b> широкий тейк (2%) + узкий стоп (0.5%, R:R 4:1) — лучшая реалистичная пара. SL 0.3% номинально выше, но нереален (спред+слип).<br>`+
`• <b>Тайм-стоп:</b> в диапазоне 3-30м почти не влияет (всё ~+0.34…+0.40, в пределах шума n=${RC.n}). Дисбаланс решается быстро. Твои 10м — рабочие.<br>`+
`<b>Под лайв:</b> окно 0.5% + антиспуф + TP 2% / SL 0.5% / тайм-стоп 5-10м, вход maker, только сильный квартиль.`;
document.getElementById('ideas').innerHTML=
`<b>💡 Что ещё можно улучшить (по данным):</b><ul>`+
`<li><b>Порог эмита резко вверх.</b> Эдж только в Q4 (сильнейшие). 75% сигналов — шум/минус. На окне 0.5% сильный квартиль = <b>|imb|>${c05.lo}</b> (≈ 8-9× перекос стен) — эмитить только его.</li>`+
`<li><b>Антиспуф встроить в сам сканер</b> (не только в бэктест): стену в imbalance засчитывать, только если она держится ≥2 тика стакана. Это и есть главный рычаг (+0.1-0.15% к Q4).</li>`+
`<li><b>Окно 0.5% вместо ±3%</b> — считать перекос только по стенам в пределах стопа (0.5%). Дальние стены = шум.</li>`+
`<li><b>Дедуп по кластеру.</b> ${D.per_symbol[0].sym} дал ${D.per_symbol[0].n}/${D.q4_n} сделок Q4 — эдж сконцентрирован. Серия сигналов по одному символу за минуты = одна ставка, а не ${D.per_symbol[0].n}. Кулдаун на символ + лимит одновременных позиций.</li>`+
`<li><b>Фильтр ликвидности символа.</b> Микрокапы (LIT −0.16) шумят. Гейт по объёму/глубине стакана отсечёт мусорные альты.</li>`+
`<li><b>Стена не должна «съедаться».</b> Идея на будущее: если ту сторону, куда ставим, начинают активно пробивать (стена тает по объёму) — отменять вход. Нужен трекинг изменения стены, не снапшот.</li>`+
`</ul>`;
document.getElementById('foot').textContent='depth.db path-resolved · окно 0.1%-бакеты · антиспуф ≥2 снапшота · maker 0.036% · единая шкала · Бендер';
</script>
</body></html>