Files

600 lines
297 KiB
HTML
Raw Permalink Normal View History

2026-06-08 10:36:15 +02:00
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Forex Navigator — 61 EA + 11 AI Tools</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap');
:root {
--bg: #07070d; --surface: #0d0d18; --surface2: #14142a; --surface3: #1c1c3a;
--border: rgba(255,255,255,0.06); --border-hover: rgba(255,255,255,0.12);
--text: #e8e8f0; --text-dim: #8888aa; --text-muted: #55557a;
--accent: #00d4aa; --accent2: #7c5cfc; --accent3: #f59e0b;
--blue: #5b9cf5; --pink: #ec4899; --red: #ef4444; --orange: #f59e0b; --green: #00d4aa; --purple: #a855f7; --teal: #14b8a6;
--radius: 12px; --radius-sm: 8px; --radius-lg: 16px;
}
* { margin:0; padding:0; box-sizing:border-box; }
html { scroll-behavior:smooth; }
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
background: var(--bg); color: var(--text); line-height: 1.6; overflow-x:hidden;
}
a { color:var(--accent); text-decoration:none; } a:hover { text-decoration:underline; }
/* ── Scrollbar ── */
::-webkit-scrollbar { width:6px; }
::-webkit-scrollbar-track { background:var(--bg); }
::-webkit-scrollbar-thumb { background:var(--surface3); border-radius:3px; }
::-webkit-scrollbar-thumb:hover { background:var(--text-muted); }
/* ── Animated bg ── */
.bg-glow {
position:fixed; top:-50%; left:-50%; width:200%; height:200%;
background: radial-gradient(ellipse at 30% 20%, rgba(0,212,170,0.03) 0%, transparent 50%),
radial-gradient(ellipse at 70% 80%, rgba(124,92,252,0.03) 0%, transparent 50%);
pointer-events:none; z-index:0;
}
/* ── Header ── */
header {
position:relative; z-index:10; text-align:center; padding:3rem 1rem 2rem;
border-bottom: 1px solid var(--border);
background: linear-gradient(180deg, rgba(0,212,170,0.04) 0%, transparent 100%);
}
header .logo {
display:inline-flex; align-items:center; gap:0.5rem; margin-bottom:0.5rem;
font-size:2.6rem; font-weight:800; letter-spacing:-0.02em;
background: linear-gradient(135deg, var(--accent), var(--accent2), var(--accent3));
-webkit-background-clip:text; -webkit-text-fill-color:transparent; background-clip:text;
}
header .logo span { font-size:1rem; font-weight:300; color:var(--text-dim); -webkit-text-fill-color:var(--text-dim); }
header p { color:var(--text-dim); font-size:1rem; max-width:600px; margin:0 auto; }
/* ── Stats ── */
.stats {
position:relative; z-index:10; display:flex; justify-content:center; gap:2rem;
padding:1.2rem; flex-wrap:wrap; background:var(--surface); border-bottom:1px solid var(--border);
}
.stat-item { text-align:center; position:relative; }
.stat-item::after {
content:''; position:absolute; right:-1rem; top:10%; height:80%; width:1px; background:var(--border);
}
.stat-item:last-child::after { display:none; }
.stat-value { font-size:1.6rem; font-weight:700; color:var(--accent); letter-spacing:-0.03em; }
.stat-label { font-size:0.7rem; color:var(--text-dim); text-transform:uppercase; letter-spacing:0.08em; margin-top:2px; }
/* ── Search & Filters Bar ── */
.top-bar {
position:sticky; top:0; z-index:100; background:rgba(7,7,13,0.85); backdrop-filter:blur(16px);
border-bottom:1px solid var(--border); padding:0.7rem 1rem;
display:flex; flex-wrap:wrap; align-items:center; gap:0.6rem;
}
.search-box { flex:1; min-width:200px; position:relative; }
.search-box input {
width:100%; padding:0.55rem 0.8rem 0.55rem 2.2rem; border-radius:10px;
border:1px solid var(--border); background:var(--surface2); color:var(--text);
font-size:0.85rem; font-family:'Inter',sans-serif; outline:none;
transition: border-color 0.2s, box-shadow 0.2s;
}
.search-box input:focus { border-color:var(--accent); box-shadow:0 0 0 3px rgba(0,212,170,0.1); }
.search-box::before { content:'🔍'; position:absolute; left:0.7rem; top:50%; transform:translateY(-50%); font-size:0.8rem; filter:grayscale(0.5); }
.tabs {
display:flex; gap:0.3rem; background:var(--surface2); padding:0.25rem;
border-radius:10px; border:1px solid var(--border);
}
.tab {
padding:0.4rem 1rem; border-radius:8px; font-size:0.8rem; font-weight:500;
cursor:pointer; transition:all 0.2s; color:var(--text-dim); white-space:nowrap; border:none;
background:transparent; font-family:'Inter',sans-serif;
}
.tab:hover { color:var(--text); }
.tab.active { background:var(--surface3); color:var(--accent); box-shadow:0 2px 8px rgba(0,0,0,0.3); }
.tab .badge {
display:inline-block; background:var(--surface3); padding:0.05rem 0.4rem;
border-radius:6px; font-size:0.65rem; margin-left:0.3rem; color:var(--text-dim);
}
.tab.active .badge { background:rgba(0,212,170,0.15); color:var(--accent); }
.filter-row {
display:flex; gap:0.3rem; flex-wrap:wrap; align-items:center;
}
.filter-chip {
padding:0.25rem 0.65rem; border-radius:20px; font-size:0.72rem; font-weight:500;
cursor:pointer; border:1px solid var(--border); background:transparent;
color:var(--text-dim); transition:all 0.15s; font-family:'Inter',sans-serif; white-space:nowrap;
}
.filter-chip:hover { border-color:var(--text-dim); color:var(--text); }
.filter-chip.active { color:#000; border-color:transparent; font-weight:600; }
.filter-chip.all.active { background:var(--text-dim); color:#000; }
/* ── Layout ── */
.layout { display:flex; max-width:1440px; margin:0 auto; min-height:calc(100vh - 200px); position:relative; z-index:5; }
/* ── Sidebar ── */
.sidebar {
width:230px; min-width:230px; padding:1rem 0.8rem;
border-right:1px solid var(--border); position:sticky; top:60px;
height:calc(100vh - 60px); overflow-y:auto; background:var(--bg);
}
.sidebar-label {
font-size:0.65rem; text-transform:uppercase; letter-spacing:0.1em; color:var(--text-muted);
padding:0 0.5rem; margin:1.2rem 0 0.5rem;
}
.sidebar-label:first-child { margin-top:0; }
.sidebar-btn {
display:flex; align-items:center; gap:0.4rem; padding:0.35rem 0.6rem;
border-radius:8px; color:var(--text-dim); font-size:0.8rem;
cursor:pointer; transition:all 0.12s; border:none; background:transparent;
width:100%; text-align:left; font-family:'Inter',sans-serif;
}
.sidebar-btn:hover { background:var(--surface2); color:var(--text); }
.sidebar-btn.active { background:var(--surface2); color:var(--accent); }
.sidebar-btn .count {
margin-left:auto; background:var(--surface2); padding:0 0.45rem;
border-radius:8px; font-size:0.65rem; color:var(--text-dim);
}
.sidebar-dot { width:7px; height:7px; border-radius:50%; flex-shrink:0; }
/* ── Main content ── */
.main { flex:1; padding:1.2rem; overflow-y:auto; }
/* ── Cards Grid ── */
.card-grid {
display:grid; grid-template-columns:repeat(auto-fill,minmax(340px,1fr));
gap:0.8rem; margin-bottom:2rem;
}
.card {
background:var(--surface); border:1px solid var(--border);
border-radius:var(--radius); padding:1rem;
transition:all 0.3s cubic-bezier(0.4,0,0.2,1); cursor:pointer;
position:relative; overflow:hidden;
}
.card::before {
content:''; position:absolute; top:0; left:0; right:0; height:2px;
background:linear-gradient(90deg, var(--accent), var(--accent2));
opacity:0; transition:opacity 0.3s;
}
.card:hover {
border-color:var(--border-hover); transform:translateY(-2px);
box-shadow:0 8px 30px rgba(0,212,170,0.06);
}
.card:hover::before { opacity:1; }
.card-top { display:flex; justify-content:space-between; align-items:flex-start; margin-bottom:0.5rem; }
.card-num {
display:inline-flex; align-items:center; justify-content:center;
width:26px; height:26px; border-radius:7px; background:var(--surface2);
color:var(--text-dim); font-size:0.7rem; font-weight:600; flex-shrink:0;
}
.card h3 { font-size:0.9rem; font-weight:600; flex:1; margin:0 0.5rem; word-break:break-word; color:var(--text); }
.card-tags { display:flex; gap:0.3rem; flex-wrap:wrap; margin-bottom:0.4rem; }
.card-tag {
display:inline-block; padding:0.08rem 0.45rem; border-radius:4px;
font-size:0.63rem; background:var(--surface2); color:var(--text-dim);
}
.tag-mt4 { background:rgba(91,156,245,0.12) !important; color:var(--blue) !important; }
.tag-mt5 { background:rgba(236,72,153,0.12) !important; color:var(--pink) !important; }
.tag-py { background:rgba(168,85,247,0.12) !important; color:var(--purple) !important; }
.card-desc {
font-size:0.76rem; color:var(--text-dim); line-height:1.5;
display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden;
}
.card-actions {
display:flex; gap:0.4rem; margin-top:0.6rem; flex-wrap:wrap;
}
.card-actions a, .card-actions button {
display:inline-flex; align-items:center; gap:0.25rem; padding:0.2rem 0.6rem;
border-radius:6px; font-size:0.72rem; border:1px solid var(--border);
background:transparent; color:var(--text-dim); cursor:pointer;
transition:all 0.15s; font-family:'Inter',sans-serif;
}
.card-actions a:hover, .card-actions button:hover {
background:var(--surface2); border-color:var(--accent); color:var(--text); text-decoration:none;
}
.card-risk {
display:inline-flex; align-items:center; font-size:0.62rem; font-weight:600;
padding:0.08rem 0.45rem; border-radius:4px; flex-shrink:0;
}
/* ── Modal ── */
.modal-overlay {
display:none; position:fixed; inset:0; z-index:1000;
background:rgba(0,0,0,0.7); backdrop-filter:blur(8px);
justify-content:center; align-items:center; padding:1rem;
}
.modal-overlay.open { display:flex; }
.modal {
background:var(--surface); border:1px solid var(--border);
border-radius:var(--radius-lg); width:100%; max-width:720px;
max-height:90vh; overflow-y:auto; padding:1.5rem;
animation:modalIn 0.25s ease-out;
}
@keyframes modalIn {
from { opacity:0; transform:scale(0.95) translateY(10px); }
to { opacity:1; transform:scale(1) translateY(0); }
}
.modal-close {
float:right; width:32px; height:32px; border-radius:8px; border:1px solid var(--border);
background:var(--surface2); color:var(--text-dim); cursor:pointer;
display:flex; align-items:center; justify-content:center; font-size:1.1rem;
transition:all 0.15s; font-family:'Inter',sans-serif;
}
.modal-close:hover { background:var(--surface3); color:var(--text); }
.modal h2 { font-size:1.3rem; font-weight:700; margin-bottom:0.3rem; }
.modal .modal-meta { display:flex; gap:0.5rem; flex-wrap:wrap; margin-bottom:1rem; }
.modal-section { margin-top:0.8rem; }
.modal-section:first-of-type { margin-top:0; }
.modal-section .ms-label {
font-size:0.65rem; text-transform:uppercase; letter-spacing:0.08em;
color:var(--text-muted); margin-bottom:0.2rem;
}
.modal-section .ms-label::before { content:'▪ '; color:var(--accent); }
.modal-section .ms-content {
font-size:0.82rem; color:var(--text); line-height:1.7;
background:rgba(0,0,0,0.2); padding:0.5rem 0.6rem; border-radius:6px;
white-space:pre-wrap; font-family:'Inter',sans-serif;
}
.modal .modal-links { display:flex; gap:0.5rem; margin-top:1rem; flex-wrap:wrap; }
.modal .modal-links a {
display:inline-flex; align-items:center; gap:0.3rem; padding:0.4rem 1rem;
border-radius:8px; font-size:0.8rem; border:1px solid var(--border);
transition:all 0.15s;
}
.modal .modal-links a:hover { background:var(--surface2); border-color:var(--accent); text-decoration:none; }
/* ── Tab Panels ── */
.tab-panel { display:none; }
.tab-panel.active { display:block; }
.empty-state {
text-align:center; padding:3rem; color:var(--text-dim);
}
.empty-state h3 { font-size:1.2rem; margin-bottom:0.5rem; }
/* ── Responsive ── */
@media (max-width:900px) { .sidebar { display:none; } }
@media (max-width:640px) {
.card-grid { grid-template-columns:1fr; }
.top-bar { flex-direction:column; }
.tabs { width:100%; justify-content:center; }
.search-box { width:100%; }
.stats { gap:1rem; }
.stat-item::after { display:none; }
header .logo { font-size:2rem; }
}
/* ── Empty state ── */
#noResults {
display:none; text-align:center; padding:3rem; color:var(--text-dim);
}
#noResults h3 { font-size:1.2rem; margin-bottom:0.3rem; }
</style>
</head>
<body>
<div class="bg-glow"></div>
<header>
<div class="logo">Forex Navigator <span>v2.0</span></div>
<p>Коллекция Expert Advisors для MT4/MT5 и AI/ML инструментов для автоматической торговли</p>
</header>
<div class="stats">
<div class="stat-item"><div class="stat-value">61</div><div class="stat-label">Советников EA</div></div>
<div class="stat-item"><div class="stat-value">40</div><div class="stat-label">MT4</div></div>
<div class="stat-item"><div class="stat-value">21</div><div class="stat-label">MT5</div></div>
<div class="stat-item"><div class="stat-value">43</div><div class="stat-label">Стратегий</div></div>
<div class="stat-item"><div class="stat-value">11</div><div class="stat-label">AI/ML проектов</div></div>
</div>
<div class="top-bar">
<div class="tabs" id="mainTabs">
<button class="tab active" onclick="switchTab('all')">Все EA <span class="badge">61</span></button>
<button class="tab" onclick="switchTab('categories')">По категориям</button>
<button class="tab" onclick="switchTab('ai')">AI/ML Tools <span class="badge">11</span></button>
</div>
<div class="search-box"><input type="text" id="searchInput" onkeyup="doSearch()" placeholder="Поиск по названию, стратегии, паре..."></div>
</div>
<div class="layout">
<div class="sidebar" id="sidebar">
<div class="sidebar-label">Уровень риска</div>
<button class="sidebar-btn active" data-filter="risk_all" onclick="setFilter('risk','all')"><span class="sidebar-dot" style="background:var(--text-dim)"></span>Все</button>
<button class="sidebar-btn" data-filter="risk_low" onclick="setFilter('risk','low')"><span class="sidebar-dot" style="background:var(--green)"></span>Низкий</button>
<button class="sidebar-btn" data-filter="risk_medium" onclick="setFilter('risk','medium')"><span class="sidebar-dot" style="background:var(--blue)"></span>Средний</button>
<button class="sidebar-btn" data-filter="risk_high" onclick="setFilter('risk','high')"><span class="sidebar-dot" style="background:var(--orange)"></span>Высокий</button>
<button class="sidebar-btn" data-filter="risk_very_high" onclick="setFilter('risk','very_high')"><span class="sidebar-dot" style="background:var(--red)"></span>Очень высокий</button>
<button class="sidebar-btn" data-filter="risk_protective" onclick="setFilter('risk','protective')"><span class="sidebar-dot" style="background:var(--teal)"></span>Защитные</button>
<div class="sidebar-label">Платформа</div>
<button class="sidebar-btn" data-filter="plat_all" onclick="setFilter('plat','all')"><span class="sidebar-dot" style="background:var(--accent)"></span>Все</button>
<button class="sidebar-btn" data-filter="plat_mt4" onclick="setFilter('plat','MT4')"><span class="sidebar-dot" style="background:var(--blue)"></span>MT4</button>
<button class="sidebar-btn" data-filter="plat_mt5" onclick="setFilter('plat','MT5')"><span class="sidebar-dot" style="background:var(--pink)"></span>MT5</button>
<button class="sidebar-btn" data-filter="plat_python" onclick="setFilter('plat','Python')"><span class="sidebar-dot" style="background:var(--purple)"></span>Python</button>
<div class="sidebar-label">Категории</div>
<div id="catSidebar"></div>
<div style="margin-top:1rem;padding:0.3rem">
<button class="sidebar-btn" onclick="resetFilters()" style="color:var(--accent);font-size:0.75rem">⟳ Сбросить всё</button>
</div>
</div>
<div class="main">
<div id="noResults"><h3>😕 Ничего не найдено</h3><p>Попробуйте изменить параметры поиска или фильтры</p></div>
<!-- Tab: All EA -->
<div class="tab-panel active" id="panel-all"><div class="card-grid" id="allGrid"></div></div>
<!-- Tab: Categories -->
<div class="tab-panel" id="panel-categories"><div id="catGrids"></div></div>
<!-- Tab: AI Tools -->
<div class="tab-panel" id="panel-ai"><div class="card-grid" id="aiGrid"></div></div>
</div>
</div>
<!-- Modal -->
<div class="modal-overlay" id="modalOverlay" onclick="closeModal(event)">
<div class="modal" id="modalContent" onclick="event.stopPropagation()">
<button class="modal-close" onclick="closeModal()"></button>
<div id="modalBody"></div>
</div>
</div>
<footer style="text-align:center;padding:1.5rem;border-top:1px solid var(--border);color:var(--text-muted);font-size:0.8rem;position:relative;z-index:5">
Forex Navigator · 61 Expert Advisors · 11 AI/ML Tools · Собрано и организовано Hermes AI
</footer>
<script>
// ─── Data ───
const EA = [{"id": "01-GridEA", "num": "01", "name": "GridEA", "strategy": "Grid", "platform": "MT4", "mq_file": "GridEA.mq4", "pdf_file": "GridEA.pdf", "file_size": 2.8, "risk_level": "Высокий", "risk_color": "#f59e0b", "aggression": "high", "short_desc": "Советник реализует классическую грид-стратегию (сеточную торговлю) для MetaTrader 4. Сеточная торговля — это метод, при котором выставляются серии отложенных ордеров Buy и Sell на фиксированных рассто", "description": "Советник реализует классическую грид-стратегию (сеточную торговлю) для MetaTrader 4. Сеточная торговля — это метод, при котором выставляются серии отложенных ордеров Buy и Sell на фиксированных расстояниях друг от друга, образуя «сетку» уровней. Когда цена движется, она пересекает эти уровни, и каждый раз срабатывает тейк-профит по одному ордеру и открывается новый противоположный ордер на соседнем уровне. Таким образом, советник зарабатывает на каждом мелком колебании цены внутри диапазона. Стратегия наиболее эффективна в боковых рынках с низкой волатильностью, где цена колеблется в определённом коридоре. Особенность GridEA — простой и прозрачный код без мартингейла, что позволяет точно контролировать риски.", "how_it_works": "Шаг 1: Задаются параметры сетки — расстояние между уровнями (шаг), количество уровней, стартовый объём лота.\nШаг 2: Советник рассчитывает ценовые уровни для установки отложенных ордеров.\nШаг 3: При каждом пересечении ценой уровня — срабатывает тейк-профит по открытому ордеру, и на противоположной стороне открывается новый ордер.\nШаг 4: Если цена выходит за крайние уровни сетки, срабатывает стоп-лосс. Мартингейл не используется — каждый ордер имеет фиксированный объём.\nШаг 5: Советник продолжает работу до ручной остановки или срабатывания общего стоп-лосса.", "params": "Шаг сетки (Step): 10-30 пунктов — расстояние между соседними уровнями. Меньший шаг = больше сделок, но выше риск.\nКоличество уровней (Levels): 5-15 — общее число ордеров в сетке.\nОбъём лота (Lot Size): 0.01-0.1 — фиксированный объём каждого ордера.\nТейк-профит (Take Profit): 5-15 пунктов — прибыль на один ордер.\nMagic Number: 12345 — уникальный идентификатор ордеров советника.", "pairs": "EURUSD, GBPUSD, USDJPY, USDCHF — основные валютные пары в состоянии боковика (когда цена колеблется в диапазоне). Не рекомендуется использовать на XAUUSD (золото) из-за высокой волатильности, которая может пробить сетку.", "timeframe": "M5 (5 минут), M15 (15 минут), M30 (30 минут). О
const AI = [{"id": "claude-trader", "full_name": "Claude Trader (El-Bach)", "url": "https://github.com/El-Bach/claude-trader", "stars": 4, "type_name": "AI-агенты", "platform": "MT5", "lang": "Python + MQL5", "risk_level": "Экспериментальный", "risk_color": "#a855f7", "short_desc": "Фреймворк для автономной торговли с использованием 14 AI-агентов Claude. Каждый агент отвечает за свою роль: дневной стратег, специалист по входу, риск-менеджер, аналитик рынка, трейдер-исполнитель и ", "description": "Фреймворк для автономной торговли с использованием 14 AI-агентов Claude. Каждый агент отвечает за свою роль: дневной стратег, специалист по входу, риск-менеджер, аналитик рынка, трейдер-исполнитель и другие. Интегрируется с MT5 через MetaTrader5 Python API. Агенты взаимодействуют через единый контекст, принимая коллективные решения по торговле. Поддерживает EURUSD, XAUUSD, GBPUSD, USDJPY.", "how_it_works": "14 AI-агентов работают в коллаборативном режиме:\n1. Strategist — анализирует рынок и определяет общее направление дня\n2. Entry Specialist — находит оптимальные точки входа\n3. Risk Manager — контролирует риски и размер позиции\n4. Market Analyst — анализирует фундаментальные и технические факторы\n5. Executor — размещает ордера в MT5 через Python API\n6. Performance Analyst — оценивает результаты и корректирует стратегию\n7-14: дополнительные узкоспециализированные агенты\n\nРешения принимаются консенсусом (голосованием) между агентами.", "params": "14 AI-агентов Claude\nPython + MetaTrader5 API\nРежим: совет/консенсус\nРаботает 24/7\nТребуется API ключ Anthropic Claude\nБрокер: любой MT5\nРекомендуемый депозит: от $500 (демо сначала)", "pairs": "EURUSD, XAUUSD, GBPUSD, USDJPY", "timeframe": "H1, H4, Daily", "best_pairs": "Основные пары: EURUSD, XAUUSD, GBPUSD, USDJPY. Начинайте с EURUSD, так как это самая ликвидная пара с наименьшим спредом.", "risk_mgmt": "ЭКСПЕРИМЕНТАЛЬНЫЙ ПРОЕКТ. AI-агенты могут принимать неожиданные решения. Требуется тщательное наблюдение. Начинайте с демо-счёта. Не рискуйте более 1% на сделку. Ограничьте максимальное дневное количество сделок. Установите Account Protector для авто-остановки при просадке 15%. Код требует доработки — проверяйте каждый запуск.", "setup_tips": "1. Установите Python + MetaTrader5 библиотеку\n2. Получите API ключ Anthropic Claude\n3. Настройте MT5 терминал для Python-подключения\n4. Запустите главный скрипт trading_agent.py\n5. Наблюдайте за решениями AI-агентов\n6. После тестов на демо — микро-реальный счёт"}, {"id": "mt5-trading-mcp", "full_name": "MT5 Trading MCP Server", "url": "https://github.com/vincentwongso/mt5-trading-mcp", "stars": 2, "type_name": "MCP / AI-интеграция", "platform": "MT5", "lang": "Python", "
const CATS = {"grid": {"name": "Grid", "color": "#00d4aa", "count": 2}, "grid-+-martingale": {"name": "Grid + Martingale", "color": "#7c5cfc", "count": 1}, "martingale": {"name": "Martingale", "color": "#f59e0b", "count": 2}, "hedge-+-grid": {"name": "Hedge + Grid", "color": "#5b9cf5", "count": 1}, "hedge": {"name": "Hedge", "color": "#ec4899", "count": 2}, "hedge-straddle": {"name": "Hedge (Straddle)", "color": "#ef4444", "count": 1}, "trend": {"name": "Trend", "color": "#14b8a6", "count": 3}, "trend-ma": {"name": "Trend (MA)", "color": "#f97316", "count": 1}, "trend-ma-cross": {"name": "Trend (MA Cross)", "color": "#a855f7", "count": 2}, "trend-ema": {"name": "Trend (EMA)", "color": "#06b6d4", "count": 1}, "trend-bollinger": {"name": "Trend (Bollinger)", "color": "#84cc16", "count": 1}, "trend-ichimoku": {"name": "Trend (Ichimoku)", "color": "#e22", "count": 1}, "trend-price-action": {"name": "Trend (Price Action)", "color": "#00d4aa", "count": 1}, "trend-turtle": {"name": "Trend (Turtle)", "color": "#7c5cfc", "count": 1}, "trend-modular": {"name": "Trend (Modular)", "color": "#f59e0b", "count": 1}, "trend-pullback": {"name": "Trend (Pullback)", "color": "#5b9cf5", "count": 1}, "scalper": {"name": "Scalper", "color": "#ec4899", "count": 1}, "scalper-atr": {"name": "Scalper (ATR)", "color": "#ef4444", "count": 1}, "scalper-pattern": {"name": "Scalper (Pattern)", "color": "#14b8a6", "count": 1}, "scalper-rsi": {"name": "Scalper (RSI)", "color": "#f97316", "count": 1}, "scalper-stochastic": {"name": "Scalper (Stochastic)", "color": "#a855f7", "count": 1}, "scalper-sar": {"name": "Scalper (SAR)", "color": "#06b6d4", "count": 1}, "breakout": {"name": "Breakout", "color": "#84cc16", "count": 1}, "breakout-orb": {"name": "Breakout (ORB)", "color": "#e22", "count": 1}, "breakout-asian": {"name": "Breakout (Asian)", "color": "#00d4aa", "count": 1}, "breakout-trendline": {"name": "Breakout (Trendline)", "color": "#7c5cfc", "count": 1}, "breakout-range": {"name": "Breakout (Range)", "color": "#f59e0b", "count": 1}, "s-r-+-martingale": {"name": "S/R + Martingale", "color": "#5b9cf5", "count": 1}, "multi-strategy": {"name": "Multi-Strategy", "color": "#ec4899", "count": 1}, "multi-strategy-ict": {"name": "Multi-Strategy (ICT)", "color": "#ef4444", "count": 1}, "ict---imbalance": {"name": "ICT / Imbalance", "color": "#14b8a6", "count": 1}, "ict---mitigation": {"name": "ICT / Mitigation", "color": "#f97316", "count": 1}, "ai---trend": {"name": "AI / Trend", "color": "#a855f7", "count": 1}, "order-blocks": {"name": "Order Blocks", "color": "#06b6d4", "count": 1}, "macd": {"name": "MACD", "color": "#84cc16", "count": 2}, "nnfx": {"name": "NNFX", "color": "#e22", "count": 3}, "mean-reversion": {"name": "Mean Reversion", "color": "#00d4aa", "count": 3}, "news": {"name": "News", "color": "#7c5cfc", "count": 2}, "pattern": {"name": "Pattern", "color": "#f59e0b", "count": 1}, "single-logic": {"name": "Single Logic", "color": "#5b9cf5", "count": 2}, "random": {"name": "Random", "color": "#ec4899", "count": 1}, "unique-ma": {"name": "Unique (MA)", "color": "#ef4444", "count": 1}, "utility": {"name": "Utility", "color": "#14b8a6", "count": 6}};
let activeTab = 'all';
let filters = { risk: 'all', plat: 'all' };
let searchQuery = '';
const riskColors = { low:'#00d4aa', medium:'#5b9cf5', high:'#f59e0b', very_high:'#ef4444', experimental:'#a855f7', protective:'#14b8a6' };
function esc(s) { return String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;') }
function riskBadge(level, color) {
return `<span class="card-risk" style="background:${color}18;color:${color}">${esc(level)}</span>`;
}
function buildEACard(e) {
const bc = e.platform === 'MT5' ? 'tag-mt5' : 'tag-mt4';
return `<div class="card" onclick="openEAModal('${e.id}')" data-name="${e.name.toLowerCase()}" data-strategy="${e.strategy.toLowerCase()}" data-platform="${e.platform.toLowerCase()}" data-risk="${e.aggression}">
<div class="card-top">
<span class="card-num">${e.num}</span>
<h3>${esc(e.name)}</h3>
${riskBadge(e.risk_level, e.risk_color)}
</div>
<div class="card-tags">
<span class="card-tag ${bc}">${e.platform}</span>
<span class="card-tag">${esc(e.strategy)}</span>
<span class="card-tag">${e.file_size} KB</span>
</div>
<div class="card-desc">${esc(e.short_desc)}</div>
<div class="card-actions">
<a href="${e.folder}/${e.mq_file}" download onclick="event.stopPropagation()">⬇ .mq${e.platform==='MT4'?'4':'5'}</a>
<a href="${e.folder}/${e.pdf_file}" target="_blank" onclick="event.stopPropagation()">📕 PDF</a>
<button onclick="event.stopPropagation();openEAModal('${e.id}')">📖 Подробнее</button>
</div>
</div>`;
}
function buildAICard(t) {
const rc = t.risk_color || '#a855f7';
return `<div class="card" onclick="openAIModal('${t.id}')" data-name="${t.full_name.toLowerCase()}" data-strategy="${t.type_name.toLowerCase()}" data-platform="${t.platform.toLowerCase()}" data-risk="experimental">
<div class="card-top">
<span class="card-num" style="background:rgba(168,85,247,0.15);color:var(--purple)">★</span>
<h3>${esc(t.full_name)}</h3>
${riskBadge(t.risk_level, rc)}
</div>
<div class="card-tags">
<span class="card-tag" style="background:rgba(168,85,247,0.12);color:var(--purple)">${esc(t.type_name)}</span>
<span class="card-tag { 'tag-mt5' if 'mt5' in t.platform.lower() else 'tag-py' if 'python' in t.platform.lower() else '' }">${esc(t.platform)}</span>
<span class="card-tag">${esc(t.lang)}</span>
<span class="card-tag">⭐${t.stars}</span>
</div>
<div class="card-desc">${esc(t.short_desc)}</div>
<div class="card-actions">
<a href="${t.url}" target="_blank">🔗 GitHub</a>
<button onclick="event.stopPropagation();openAIModal('${t.id}')">📖 Подробнее</button>
</div>
</div>`;
}
// ─── Render ───
function renderAll() {
let items = EA.filter(e => matches(e));
document.getElementById('allGrid').innerHTML = items.length
? items.map(buildEACard).join('')
: '<div class="empty-state"><h3>😕 Ничего не найдено</h3><p>Попробуйте изменить фильтры</p></div>';
}
function renderCategories() {
let html = '';
for (const [cid, cat] of Object.entries(CATS)) {
const items = EA.filter(e => {
const cid2 = e.strategy.toLowerCase().replace(/ /g,'-').replace(/\//g,'-').replace(/\(/g,'').replace(/\)/g,'');
return cid2 === cid && matches(e);
});
if (items.length === 0 && (filters.risk !== 'all' || filters.plat !== 'all' || searchQuery)) continue;
html += `<div class="section-title" style="display:flex;align-items:center;gap:0.5rem;font-size:1.1rem;margin:1.2rem 0 0.6rem;padding-bottom:0.3rem;border-bottom:1px solid var(--border)">
<span class="sidebar-dot" style="width:10px;height:10px;background:${cat.color}"></span>${cat.name} <span style="font-size:0.75rem;color:var(--text-muted)">${items.length} EA</span>
</div>
<div class="card-grid">${items.map(buildEACard).join('')}</div>`;
}
document.getElementById('catGrids').innerHTML = html || '<div class="empty-state"><h3>😕 Ничего не найдено</h3></div>';
}
function renderAI() {
let items = AI;
if (searchQuery) {
const q = searchQuery.toLowerCase();
items = items.filter(t => t.full_name.toLowerCase().includes(q) || t.type_name.toLowerCase().includes(q) || t.lang.toLowerCase().includes(q));
}
document.getElementById('aiGrid').innerHTML = items.length
? items.map(buildAICard).join('')
: '<div class="empty-state"><h3>😕 Ничего не найдено</h3><p>Попробуйте другой запрос</p></div>';
}
function matches(e) {
if (searchQuery) {
const q = searchQuery.toLowerCase();
if (!e.name.toLowerCase().includes(q) && !e.strategy.toLowerCase().includes(q) && !e.pairs.toLowerCase().includes(q)) return false;
}
if (filters.risk !== 'all' && e.aggression !== filters.risk) return false;
if (filters.plat !== 'all' && e.platform.toLowerCase() !== filters.plat.toLowerCase()) return false;
return true;
}
function renderAllPanels() {
renderAll(); renderCategories(); renderAI();
document.getElementById('noResults').style.display = 'none';
}
// ─── Tab navigation ───
function switchTab(tab) {
activeTab = tab;
document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
document.querySelectorAll('.tab-panel').forEach(p => p.classList.remove('active'));
document.querySelector(`.tab-panel#panel-${tab}`).classList.add('active');
document.querySelectorAll('.tabs .tab').forEach(t => {
if (t.textContent.includes(tab === 'all' ? 'Все' : tab === 'categories' ? 'категория' : 'AI')) t.classList.add('active');
});
document.getElementById('sidebar').style.display = tab === 'ai' ? 'none' : '';
}
// ─── Filters ───
function setFilter(type, value) {
filters[type] = value;
document.querySelectorAll(`[data-filter^="${type}_"]`).forEach(b => b.classList.remove('active'));
const sel = document.querySelector(`[data-filter="${type}_${value}"]`);
if (sel) sel.classList.add('active');
renderAllPanels();
}
function resetFilters() {
filters = { risk: 'all', plat: 'all' };
document.querySelectorAll('.sidebar-btn').forEach(b => b.classList.remove('active'));
document.querySelector('[data-filter="risk_all"]')?.classList.add('active');
document.querySelector('[data-filter="plat_all"]')?.classList.add('active');
searchQuery = '';
document.getElementById('searchInput').value = '';
renderAllPanels();
}
function doSearch() {
searchQuery = document.getElementById('searchInput').value;
renderAllPanels();
}
// ─── Modal ───
function openEAModal(id) {
const e = EA.find(x => x.id === id);
if (!e) return;
const body = document.getElementById('modalBody');
const sections = [
['📊 Стратегия', e.description],
['📈 Как работает', e.how_it_works],
['⚙️ Параметры', e.params],
['🎯 Валютные пары', e.best_pairs || e.pairs],
['⏱ Таймфрейм', e.timeframe],
['🛡 Управление рисками', e.risk_mgmt],
['💡 Советы по установке', e.setup_tips],
];
let shtml = sections.filter(s => s[1]).map(s =>
`<div class="modal-section"><div class="ms-label">${s[0]}</div><div class="ms-content">${esc(s[1])}</div></div>`
).join('');
body.innerHTML = `
<h2>${esc(e.name)}</h2>
<div class="modal-meta">
<span class="card-tag ${e.platform==='MT5'?'tag-mt5':'tag-mt4'}">${e.platform}</span>
<span class="card-tag">${esc(e.strategy)}</span>
${riskBadge(e.risk_level, e.risk_color)}
<span class="card-tag">${e.file_size} KB</span>
</div>
${shtml}
<div class="modal-links">
<a href="${e.folder}/${e.mq_file}" download onclick="event.stopPropagation()">⬇ Скачать .mq${e.platform==='MT4'?'4':'5'} (${e.file_size} KB)</a>
<a href="${e.folder}/${e.pdf_file}" target="_blank" onclick="event.stopPropagation()">📕 Открыть PDF</a>
</div>
`;
document.getElementById('modalOverlay').classList.add('open');
}
function openAIModal(id) {
const t = AI.find(x => x.id === id);
if (!t) return;
const body = document.getElementById('modalBody');
const sections = [
['📊 Стратегия', t.description],
['🤖 Как работает', t.how_it_works],
['⚙️ Параметры', t.params],
['🎯 Валютные пары', t.best_pairs || t.pairs],
['⏱ Таймфрейм', t.timeframe],
['🛡 Управление рисками', t.risk_mgmt],
['💡 Советы по установке', t.setup_tips],
];
let shtml = sections.filter(s => s[1]).map(s =>
`<div class="modal-section"><div class="ms-label">${s[0]}</div><div class="ms-content">${esc(s[1])}</div></div>`
).join('');
body.innerHTML = `
<h2>${esc(t.full_name)}
<span style="font-size:0.7rem;font-weight:400;color:var(--text-dim);margin-left:0.5rem">⭐${t.stars}</span>
</h2>
<div class="modal-meta">
<span class="card-tag" style="background:rgba(168,85,247,0.12);color:var(--purple)">${esc(t.type_name)}</span>
<span class="card-tag">${esc(t.platform)}</span>
<span class="card-tag">${esc(t.lang)}</span>
${riskBadge(t.risk_level, t.risk_color)}
</div>
${shtml}
<div class="modal-links">
<a href="${t.url}" target="_blank">🔗 GitHub репозиторий</a>
</div>
`;
document.getElementById('modalOverlay').classList.add('open');
}
function closeModal(e) {
if (e && e.target !== e.currentTarget) return;
document.getElementById('modalOverlay').classList.remove('open');
}
document.addEventListener('keydown', e => { if (e.key === 'Escape') closeModal(); });
// ─── Cat sidebar ───
(function buildCatSidebar() {
let html = '';
for (const [cid, cat] of Object.entries(CATS)) {
html += `<button class="sidebar-btn" onclick="switchTab('categories');document.getElementById('panel-categories').querySelector('[style*=\"margin:1.2rem\"]')?.scrollIntoView({behavior:'smooth'})">
<span class="sidebar-dot" style="background:${cat.color}"></span>${cat.name} <span class="count">${cat.count}</span>
</button>`;
}
document.getElementById('catSidebar').innerHTML = html;
})();
// ─── Init ───
renderAll();
</script>
</body>
</html>