// =============================================================
// MOCK DATA — кликабельный прототип UX/UI (не подключён к боту)
// Все цифры вымышленные. Структура повторяет реальные сущности
// dashboard: трейдеры (кошельки), позиции, watching, сделки,
// сигналы, пулы, глобальные настройки, состояние cron.
// =============================================================

window.MOCK = (function () {

    // ---- Трейдеры (кошельки) --------------------------------
    const traders = [
        {
            id: 'w1', label: 'Trader Alpha', address: '0x7f3a9c41b2e8d5f6a0c9e8d7b6a5f4e3d2c1b0a9',
            status: 'ACTIVE', rating: 4, tags: ['scalper', 'btc-only'], enabled: true,
            score: 87, grade: 'A', balance: 1240.50, roi: 24.05, netPnl: 240.50, grossPnl: 268.20,
            winrate: 62.5, maxDd: -8.2, mtmDd: -11.4, trades: 48, signals: 96, daysSilent: 0,
            source: 'HyperDash топ-100', notes: 'Стабильный скальпер по BTC/ETH. Хорошо пережил апрельскую волатильность.',
            fees: 27.7, avgRoi: 1.42, slippage: 0.021,
            spark: [4, 9, -3, 12, 7, -5, 14, 8, 3, -2, 11, 6, 9, 13],
            scoreBreakdown: { winrate: { value: '62.5%', score: 22, max: 25 }, roi: { value: '+24.1%', score: 21, max: 25 }, drawdown: { value: '-8.2%', score: 20, max: 25 }, activity: { value: '48 сделок', score: 24, max: 25 } },
            log: [
                { id: 1, at: '2026-07-01 14:22', note: 'Перевёл в ACTIVE после 3 недель теста' },
                { id: 2, at: '2026-06-14 09:10', note: 'Поднял scale_factor до 0.15 — стабильные входы' },
                { id: 3, at: '2026-06-02 18:40', note: 'Добавлен из топа HyperDash' },
            ],
            overrides: { scale_factor: 0.15, poll_interval_minutes: 1 },
        },
        {
            id: 'w2', label: 'Whale Watcher', address: '0x1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c',
            status: 'ACTIVE', rating: 5, tags: ['swing', 'low-risk'], enabled: true,
            score: 78, grade: 'B', balance: 1486.20, roi: 48.62, netPnl: 486.20, grossPnl: 512.44,
            winrate: 55.1, maxDd: -12.6, mtmDd: -14.9, trades: 29, signals: 41, daysSilent: 1,
            source: 'Twitter @hlwhales', notes: 'Свинг-позиции по 2-5 дней. Крупный чек, редкие входы.',
            fees: 26.2, avgRoi: 2.31, slippage: 0.018,
            spark: [12, -8, 22, 15, -4, 8, 31, -6, 18, 12, 24, -9, 16, 28],
            scoreBreakdown: { winrate: { value: '55.1%', score: 18, max: 25 }, roi: { value: '+48.6%', score: 25, max: 25 }, drawdown: { value: '-12.6%', score: 16, max: 25 }, activity: { value: '29 сделок', score: 19, max: 25 } },
            log: [{ id: 1, at: '2026-06-20 11:00', note: 'Лучший ROI в подборке — поднял рейтинг до 5★' }],
            overrides: { poll_interval_minutes: 5, telegram_notify: 1 },
        },
        {
            id: 'w3', label: 'Degen Dima', address: '0x9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e2f1a0b',
            status: 'TEST', rating: 2, tags: ['degen'], enabled: true,
            score: 41, grade: 'D', balance: 872.40, roi: -12.76, netPnl: -127.60, grossPnl: -102.10,
            winrate: 38.9, maxDd: -28.4, mtmDd: -31.2, trades: 54, signals: 130, daysSilent: 0,
            source: 'Discord', notes: 'Высокое плечо, мемкоины. Держим на минимальном scale.',
            fees: 25.5, avgRoi: -0.82, slippage: 0.045,
            spark: [-14, 22, -18, 9, -25, 31, -12, -8, 17, -21, 6, -15, 12, -19],
            scoreBreakdown: { winrate: { value: '38.9%', score: 8, max: 25 }, roi: { value: '-12.8%', score: 5, max: 25 }, drawdown: { value: '-28.4%', score: 6, max: 25 }, activity: { value: '54 сделки', score: 22, max: 25 } },
            log: [{ id: 1, at: '2026-06-28 20:15', note: 'Слил 8% за вечер на PEPE — думаю про ARCHIVE' }],
            overrides: { scale_factor: 0.05, allowed_symbols: ['BTC', 'ETH', 'SOL'] },
        },
        {
            id: 'w4', label: 'ETH Maxi', address: '0x2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d',
            status: 'ACTIVE', rating: 3, tags: ['swing'], enabled: true,
            score: 69, grade: 'B', balance: 1112.80, roi: 11.28, netPnl: 112.80, grossPnl: 129.30,
            winrate: 51.7, maxDd: -9.8, mtmDd: -10.5, trades: 31, signals: 58, daysSilent: 2,
            source: 'вручную', notes: 'Только ETH и L2. Аккуратный риск-менеджмент.',
            fees: 16.5, avgRoi: 0.96, slippage: 0.015,
            spark: [6, 3, -4, 8, 12, -2, 5, 9, -6, 4, 11, 2, -3, 7],
            scoreBreakdown: { winrate: { value: '51.7%', score: 16, max: 25 }, roi: { value: '+11.3%', score: 15, max: 25 }, drawdown: { value: '-9.8%', score: 19, max: 25 }, activity: { value: '31 сделка', score: 19, max: 25 } },
            log: [],
            overrides: { allowed_symbols: ['ETH', 'ARB', 'OP'] },
        },
        {
            id: 'w5', label: 'Sol Sniper', address: '0x3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e',
            status: 'WATCH', rating: 0, tags: ['scalper'], enabled: false,
            score: 58, grade: 'C', balance: 1000.00, roi: 0, netPnl: 0, grossPnl: 0,
            winrate: 47.2, maxDd: -6.1, mtmDd: -6.1, trades: 0, signals: 12, daysSilent: 4,
            source: 'HyperDash', notes: 'Наблюдаем. Копирование выключено, собираем статистику сигналов.',
            fees: 0, avgRoi: 0, slippage: 0,
            spark: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            scoreBreakdown: null, scoreReason: 'Копирование выключено — статистика по сигналам',
            log: [{ id: 1, at: '2026-07-02 10:05', note: 'Добавлен в наблюдение, 12 сигналов за 4 дня' }],
            overrides: {},
        },
        {
            id: 'w6', label: 'Grid Master', address: '0x4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f',
            status: 'ACTIVE', rating: 4, tags: ['low-risk'], enabled: true,
            score: 74, grade: 'B', balance: 1198.40, roi: 19.84, netPnl: 198.40, grossPnl: 224.80,
            winrate: 58.3, maxDd: -7.4, mtmDd: -9.1, trades: 60, signals: 84, daysSilent: 0,
            source: 'Telegram-канал', notes: 'Сеточник. Включён direct-режим с SL/TP.',
            fees: 26.4, avgRoi: 1.05, slippage: 0.019,
            spark: [3, 5, 4, -2, 6, 5, 3, 7, -1, 4, 6, 5, 8, 4],
            scoreBreakdown: { winrate: { value: '58.3%', score: 20, max: 25 }, roi: { value: '+19.8%', score: 18, max: 25 }, drawdown: { value: '-7.4%', score: 21, max: 25 }, activity: { value: '60 сделок', score: 15, max: 25 } },
            log: [],
            overrides: { execution_mode: 'direct', hl_margin_mode: 'isolated' },
        },
        {
            id: 'w7', label: 'Ghost Trader', address: '0x5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a',
            status: 'TEST', rating: 1, tags: [], enabled: true,
            score: null, grade: '?', balance: 1004.10, roi: 0.41, netPnl: 4.10, grossPnl: 5.60,
            winrate: 50.0, maxDd: -2.1, mtmDd: -2.1, trades: 4, signals: 9, daysSilent: 21,
            source: 'вручную', notes: '', scoreReason: 'Мало сделок (< 5)',
            fees: 1.5, avgRoi: 0.22, slippage: 0.02,
            spark: [0, 2, 0, 0, -1, 0, 3, 0, 0, 0, 0, 0, 0, 0],
            scoreBreakdown: null,
            log: [{ id: 1, at: '2026-06-30 16:44', note: '3 недели молчит — кандидат на архив' }],
            overrides: {},
        },
        {
            id: 'w8', label: 'Old Legend', address: '0x6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b',
            status: 'ARCHIVE', rating: 3, tags: ['swing'], enabled: false,
            score: 63, grade: 'C', balance: 1088.90, roi: 8.89, netPnl: 88.90, grossPnl: 101.20,
            winrate: 52.6, maxDd: -14.2, mtmDd: -14.2, trades: 38, signals: 60, daysSilent: 44,
            source: 'HyperDash', notes: 'Был хорош в мае.', archiveReason: 'Перестал торговать после 12 июня',
            fees: 12.3, avgRoi: 0.71, slippage: 0.02,
            spark: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            scoreBreakdown: { winrate: { value: '52.6%', score: 16, max: 25 }, roi: { value: '+8.9%', score: 13, max: 25 }, drawdown: { value: '-14.2%', score: 14, max: 25 }, activity: { value: '38 сделок', score: 20, max: 25 } },
            log: [{ id: 1, at: '2026-06-25 12:00', note: 'В архив: 2 недели без сделок' }],
            overrides: {},
        },
    ];

    // Наполнение до 100+ трейдеров — чтобы прототип показывал длинные списки
    // без вертикального скролла внутри таблиц (детерминированный генератор).
    (function () {
        const prefixes = ['Alpha', 'Bravo', 'Cobra', 'Delta', 'Echo', 'Falcon', 'Ghost', 'Hydra', 'Iron', 'Jet', 'Kilo', 'Lynx', 'Mako', 'Nova', 'Orca', 'Puma', 'Quartz', 'Raven', 'Sigma', 'Titan', 'Umbra', 'Vega', 'Wolf', 'Xeno', 'Yeti', 'Zephyr'];
        const suffixes = ['Capital', 'Trades', 'FX', 'Scalp', 'Swing', 'Whale', 'Sniper', 'Fund', 'Desk', 'Signals', 'Quant', 'Edge'];
        const tagPool = ['scalper', 'swing', 'degen', 'low-risk', 'btc-only'];
        const statuses = ['WATCH', 'TEST', 'ACTIVE', 'ACTIVE', 'ARCHIVE'];
        let seed = 987654321;
        const rnd = () => (seed = (seed * 1103515245 + 12345) & 0x7fffffff) / 0x7fffffff;
        const pick = a => a[Math.floor(rnd() * a.length)];
        for (let i = 9; i <= 112; i++) {
            const hex = '0x' + Array.from({ length: 40 }, () => '0123456789abcdef'[Math.floor(rnd() * 16)]).join('');
            const trades = Math.floor(rnd() * 90);
            const winrate = +(35 + rnd() * 35).toFixed(1);
            const roi = +((rnd() - 0.4) * 60).toFixed(2);
            const balance = +(1000 * (1 + roi / 100)).toFixed(2);
            const daysSilent = Math.floor(rnd() * 40);
            const score = trades < 5 ? null : Math.floor(30 + rnd() * 65);
            const grade = score === null ? '?' : (score >= 80 ? 'A' : score >= 65 ? 'B' : score >= 50 ? 'C' : score >= 40 ? 'D' : 'F');
            const spark = Array.from({ length: 14 }, () => +((rnd() - 0.45) * 20).toFixed(1));
            traders.push({
                id: 'w' + i,
                label: pick(prefixes) + ' ' + pick(suffixes) + (rnd() > 0.7 ? ' ' + (i) : ''),
                address: hex,
                status: pick(statuses),
                rating: Math.floor(rnd() * 6),
                tags: rnd() > 0.5 ? [pick(tagPool)] : [],
                enabled: rnd() > 0.35,
                score, grade,
                balance, roi, netPnl: +(balance - 1000).toFixed(2), grossPnl: +(balance - 1000 + rnd() * 20).toFixed(2),
                winrate, maxDd: +(-(2 + rnd() * 25)).toFixed(1), mtmDd: +(-(2 + rnd() * 28)).toFixed(1),
                trades, signals: trades + Math.floor(rnd() * 40), daysSilent,
                source: pick(['HyperDash', 'Twitter', 'Discord', 'вручную', 'Telegram-канал']), notes: '',
                fees: +(trades * 0.4).toFixed(1), avgRoi: +((rnd() - 0.4) * 3).toFixed(2), slippage: +(0.01 + rnd() * 0.04).toFixed(3),
                spark,
                scoreBreakdown: score === null ? null : {
                    winrate: { value: winrate + '%', score: Math.round(winrate / 100 * 25), max: 25 },
                    roi: { value: (roi >= 0 ? '+' : '') + roi + '%', score: Math.max(0, Math.round((roi + 24) / 60 * 25)), max: 25 },
                    drawdown: { value: '—', score: Math.floor(rnd() * 25), max: 25 },
                    activity: { value: trades + ' сделок', score: Math.min(25, Math.round(trades / 90 * 25)), max: 25 },
                },
                scoreReason: score === null ? 'Мало сделок (< 5)' : undefined,
                log: [], overrides: {},
            });
        }
    })();

    // ---- Открытые позиции -----------------------------------
    const positions = [
        { walletId: 'w1', symbol: 'BTC', side: 'long', sizeUsd: 186.40, leverage: 5, entry: 64210.5, traderEntry: 64180.0, current: 65340.2, pnlUsd: 16.42, pnlPct: 8.81, openedAt: '2026-07-05 08:14', ageMin: 250 },
        { walletId: 'w1', symbol: 'ETH', side: 'short', sizeUsd: 92.10, leverage: 3, entry: 3412.8, traderEntry: 3415.1, current: 3448.6, pnlUsd: -2.90, pnlPct: -3.15, openedAt: '2026-07-05 10:02', ageMin: 142 },
        { walletId: 'w2', symbol: 'SOL', side: 'long', sizeUsd: 240.00, leverage: 4, entry: 148.22, traderEntry: 148.05, current: 153.71, pnlUsd: 35.55, pnlPct: 14.81, openedAt: '2026-07-03 22:40', ageMin: 2270 },
        { walletId: 'w4', symbol: 'ETH', side: 'long', sizeUsd: 110.30, leverage: 2, entry: 3390.4, traderEntry: 3391.0, current: 3448.6, pnlUsd: 3.79, pnlPct: 3.43, openedAt: '2026-07-04 15:20', ageMin: 1250 },
        { walletId: 'w6', symbol: 'BTC', side: 'short', sizeUsd: 74.80, leverage: 3, entry: 65890.0, traderEntry: 65910.5, current: 65340.2, pnlUsd: 1.87, pnlPct: 2.50, openedAt: '2026-07-05 06:55', ageMin: 330 },
        { walletId: 'w3', symbol: 'WIF', side: 'long', sizeUsd: 48.20, leverage: 8, entry: 2.184, traderEntry: 2.180, current: 2.061, pnlUsd: -21.72, pnlPct: -45.06, openedAt: '2026-07-04 23:12', ageMin: 780 },
    ];

    // ---- Watching (отложенный вход по просадке) ---------------
    const watching = [
        { walletId: 'w2', symbol: 'BTC', side: 'long', leverage: 4, traderEntry: 65120.0, startedAt: '2026-07-05 09:30', ageH: 2, ageM: 42, targetPct: 5 },
        { walletId: 'w6', symbol: 'DOGE', side: 'short', leverage: 3, traderEntry: 0.1284, startedAt: '2026-07-04 19:10', ageH: 17, ageM: 2, targetPct: 3 },
        { walletId: 'w1', symbol: 'AVAX', side: 'long', leverage: 5, traderEntry: 29.84, startedAt: '2026-07-05 11:05', ageH: 1, ageM: 7, targetPct: 5 },
    ];

    // ---- Закрытые сделки --------------------------------------
    const trades = [
        { walletId: 'w1', closedAt: '2026-07-05 11:42', symbol: 'BTC', side: 'long', entry: 63980.2, exit: 64840.6, sizeUsd: 172.5, slippage: 0.02, gross: 11.62, fees: 0.24, net: 11.38, reason: 'signal' },
        { walletId: 'w3', closedAt: '2026-07-05 10:15', symbol: 'PEPE', side: 'long', entry: 0.0000121, exit: 0.0000109, sizeUsd: 52.0, slippage: 0.08, gross: -10.31, fees: 0.11, net: -10.42, reason: 'liquidation' },
        { walletId: 'w2', closedAt: '2026-07-05 08:03', symbol: 'ETH', side: 'short', entry: 3480.1, exit: 3411.9, sizeUsd: 210.0, slippage: 0.015, gross: 16.44, fees: 0.29, net: 16.15, reason: 'signal' },
        { walletId: 'w6', closedAt: '2026-07-04 23:58', symbol: 'BTC', side: 'long', entry: 64520.0, exit: 64890.3, sizeUsd: 80.0, slippage: 0.01, gross: 2.29, fees: 0.11, net: 2.18, reason: 'partial' },
        { walletId: 'w1', closedAt: '2026-07-04 21:37', symbol: 'SOL', side: 'long', entry: 145.80, exit: 149.92, sizeUsd: 96.0, slippage: 0.02, gross: 10.85, fees: 0.13, net: 10.72, reason: 'signal' },
        { walletId: 'w4', closedAt: '2026-07-04 18:22', symbol: 'ARB', side: 'long', entry: 0.842, exit: 0.828, sizeUsd: 64.0, slippage: 0.03, gross: -4.26, fees: 0.09, net: -4.35, reason: 'signal' },
        { walletId: 'w2', closedAt: '2026-07-04 14:48', symbol: 'BTC', side: 'long', entry: 63110.4, exit: 64720.8, sizeUsd: 250.0, slippage: 0.012, gross: 25.53, fees: 0.35, net: 25.18, reason: 'signal' },
        { walletId: 'w6', closedAt: '2026-07-04 11:16', symbol: 'ETH', side: 'short', entry: 3465.0, exit: 3440.2, sizeUsd: 71.0, slippage: 0.02, gross: 2.03, fees: 0.10, net: 1.93, reason: 'signal' },
        { walletId: 'w3', closedAt: '2026-07-04 03:41', symbol: 'WIF', side: 'short', entry: 2.310, exit: 2.455, sizeUsd: 45.0, slippage: 0.06, gross: -11.30, fees: 0.09, net: -11.39, reason: 'signal' },
        { walletId: 'w1', closedAt: '2026-07-03 22:19', symbol: 'BTC', side: 'short', entry: 65480.1, exit: 65120.7, sizeUsd: 160.0, slippage: 0.018, gross: 3.51, fees: 0.22, net: 3.29, reason: 'signal' },
        { walletId: 'w4', closedAt: '2026-07-03 17:53', symbol: 'ETH', side: 'long', entry: 3350.2, exit: 3420.9, sizeUsd: 120.0, slippage: 0.015, gross: 10.13, fees: 0.17, net: 9.96, reason: 'signal' },
        { walletId: 'w2', closedAt: '2026-07-03 12:30', symbol: 'HYPE', side: 'long', entry: 38.42, exit: 37.11, sizeUsd: 180.0, slippage: 0.025, gross: -24.55, fees: 0.25, net: -24.80, reason: 'signal' },
        { walletId: 'w6', closedAt: '2026-07-03 09:44', symbol: 'BTC', side: 'long', entry: 62980.0, exit: 63340.5, sizeUsd: 77.0, slippage: 0.011, gross: 1.76, fees: 0.11, net: 1.65, reason: 'partial' },
        { walletId: 'w1', closedAt: '2026-07-02 20:08', symbol: 'ETH', side: 'long', entry: 3298.7, exit: 3361.4, sizeUsd: 140.0, slippage: 0.02, gross: 10.64, fees: 0.19, net: 10.45, reason: 'signal' },
        { walletId: 'w3', closedAt: '2026-07-02 15:26', symbol: 'DOGE', side: 'long', entry: 0.1224, exit: 0.1288, sizeUsd: 58.0, slippage: 0.04, gross: 12.13, fees: 0.12, net: 12.01, reason: 'signal' },
        { walletId: 'w2', closedAt: '2026-07-02 10:12', symbol: 'SOL', side: 'long', entry: 141.30, exit: 146.85, sizeUsd: 220.0, slippage: 0.02, gross: 34.56, fees: 0.31, net: 34.25, reason: 'signal' },
    ];

    // ---- Сигналы ----------------------------------------------
    const signals = [
        { at: '2026-07-05 11:40', walletId: 'w1', symbol: 'BTC', side: 'long', size: 0.002710, mode: 'close' },
        { at: '2026-07-05 10:02', walletId: 'w1', symbol: 'ETH', side: 'short', size: 0.027000, mode: 'open' },
        { at: '2026-07-05 09:30', walletId: 'w2', symbol: 'BTC', side: 'long', size: 0.003800, mode: 'watch' },
        { at: '2026-07-05 08:14', walletId: 'w1', symbol: 'BTC', side: 'long', size: 0.002900, mode: 'open' },
        { at: '2026-07-05 08:01', walletId: 'w2', symbol: 'ETH', side: 'short', size: 0.061500, mode: 'close' },
        { at: '2026-07-04 23:56', walletId: 'w6', symbol: 'BTC', side: 'long', size: 0.000620, mode: 'partial_close' },
        { at: '2026-07-04 23:12', walletId: 'w3', symbol: 'WIF', side: 'long', size: 22.100000, mode: 'open' },
        { at: '2026-07-04 19:10', walletId: 'w6', symbol: 'DOGE', side: 'short', size: 390.000000, mode: 'watch' },
        { at: '2026-07-04 15:20', walletId: 'w4', symbol: 'ETH', side: 'long', size: 0.032500, mode: 'open' },
        { at: '2026-07-04 14:45', walletId: 'w2', symbol: 'BTC', side: 'long', size: 0.003960, mode: 'close' },
        { at: '2026-07-04 11:14', walletId: 'w6', symbol: 'ETH', side: 'short', size: 0.020500, mode: 'close' },
        { at: '2026-07-04 06:55', walletId: 'w6', symbol: 'BTC', side: 'short', size: 0.001135, mode: 'open' },
        { at: '2026-07-03 22:40', walletId: 'w2', symbol: 'SOL', side: 'long', size: 1.620000, mode: 'open' },
        { at: '2026-07-03 22:17', walletId: 'w1', symbol: 'BTC', side: 'short', size: 0.002440, mode: 'close' },
    ];

    // ---- Пулы -------------------------------------------------
    const pools = [
        {
            id: 'p1', label: 'Скальперы', enabled: true, virtualBalance: 1000, balance: 1184.20,
            roi: 18.42, tradesCount: 86, maxDd: -6.4, leverage: 3, feePct: 0.035,
            partialClose: 'off', executionMode: 'webhook', marginMode: 'isolated', subaccount: '',
            webhooks: [
                { service: 'katoshi', enabled: true, apiKey: 'ktsh_****42', botId: 12345 },
                { service: 'telegram', enabled: true, chatId: '-100123****' },
                { service: '', enabled: false },
            ],
            traders: [
                { id: 't1', label: 'Trader Alpha', address: '0x7f3a9c41b2e8d5f6a0c9e8d7b6a5f4e3d2c1b0a9', alloc: 35, sizingMode: 'percent_balance', sizingPercent: 100, leverage: null, cooldown: 30, enabled: true, drawdownEntry: false },
                { id: 't2', label: 'Grid Master', address: '0x4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f', alloc: 25, sizingMode: 'percent_balance', sizingPercent: 80, leverage: 5, cooldown: 30, enabled: true, drawdownEntry: false },
                { id: 't3', label: 'Sol Sniper', address: '0x3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e', alloc: 20, sizingMode: 'fixed', sizingFixed: 50, leverage: null, cooldown: 60, enabled: false, drawdownEntry: true, drawdownPct: 5 },
            ],
        },
        {
            id: 'p2', label: 'Свинг-пул', enabled: false, virtualBalance: 2000, balance: 1926.60,
            roi: -3.67, tradesCount: 24, maxDd: -11.8, leverage: 2, feePct: 0.035,
            partialClose: 'on', executionMode: 'direct', marginMode: 'cross', subaccount: '0xaa11…77ff',
            webhooks: [{ service: '', enabled: false }, { service: '', enabled: false }, { service: '', enabled: false }],
            traders: [
                { id: 't4', label: 'Whale Watcher', address: '0x1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c', alloc: 50, sizingMode: 'percent_balance', sizingPercent: 100, leverage: null, cooldown: 120, enabled: true, drawdownEntry: false },
                { id: 't5', label: 'ETH Maxi', address: '0x2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d', alloc: 30, sizingMode: 'percent_balance', sizingPercent: 100, leverage: 3, cooldown: 60, enabled: true, drawdownEntry: true, drawdownPct: 3 },
            ],
        },
    ];

    // ---- Графики ----------------------------------------------
    const pnlByDay = {
        labels: ['22.06', '23.06', '24.06', '25.06', '26.06', '27.06', '28.06', '29.06', '30.06', '01.07', '02.07', '03.07', '04.07', '05.07'],
        usd: [14.2, -8.6, 22.1, 9.4, -12.3, 18.7, 5.2, -3.8, 26.4, 11.9, 32.6, -14.2, 19.8, 17.1],
        pct: [1.2, -0.7, 1.9, 0.8, -1.0, 1.5, 0.4, -0.3, 2.2, 1.0, 2.7, -1.2, 1.6, 1.4],
    };
    const pnlByWeek = {
        labels: ['W19', 'W20', 'W21', 'W22', 'W23', 'W24', 'W25', 'W26', 'W27'],
        usd: [42.1, -18.4, 76.3, 51.0, 94.6, -32.2, 68.9, 88.4, 49.5],
        pct: [3.4, -1.5, 6.1, 4.0, 7.4, -2.6, 5.4, 6.8, 3.9],
    };
    const pnlByMonth = {
        labels: ['Фев', 'Мар', 'Апр', 'Май', 'Июн', 'Июл'],
        usd: [88.2, 164.5, -46.8, 212.4, 306.1, 178.9],
        pct: [7.1, 12.8, -3.9, 16.4, 22.6, 13.2],
    };
    // Кривая капитала (накопительный net PnL, $) — 40 точек
    const equity = {
        labels: ['27.05', '28.05', '29.05', '30.05', '31.05', '01.06', '02.06', '03.06', '04.06', '05.06', '06.06', '07.06', '08.06', '09.06', '10.06', '11.06', '12.06', '13.06', '14.06', '15.06', '16.06', '17.06', '18.06', '19.06', '20.06', '21.06', '22.06', '23.06', '24.06', '25.06', '26.06', '27.06', '28.06', '29.06', '30.06', '01.07', '02.07', '03.07', '04.07', '05.07'],
        values: [12, 28, 21, 45, 62, 58, 81, 96, 88, 112, 134, 121, 148, 166, 152, 177, 195, 188, 214, 232, 218, 246, 261, 240, 268, 289, 303, 294, 316, 325, 313, 332, 337, 333, 359, 371, 404, 390, 410, 427],
    };
    equity.drawdown = (function () {
        let peak = -Infinity;
        return equity.values.map(v => { peak = Math.max(peak, v); return +(v - peak).toFixed(1); });
    })();

    const bySymbol = [
        { symbol: 'BTC', net: 186.42, trades: 64, winrate: 60.9 },
        { symbol: 'ETH', net: 98.75, trades: 51, winrate: 54.9 },
        { symbol: 'SOL', net: 84.30, trades: 28, winrate: 57.1 },
        { symbol: 'HYPE', net: -41.20, trades: 17, winrate: 41.2 },
        { symbol: 'WIF', net: -33.85, trades: 22, winrate: 36.4 },
        { symbol: 'DOGE', net: 27.60, trades: 14, winrate: 57.1 },
        { symbol: 'ARB', net: -12.40, trades: 11, winrate: 45.5 },
        { symbol: 'AVAX', net: 8.91, trades: 9, winrate: 55.6 },
    ];
    const pnlDistribution = [
        { label: '< −5%', count: 28 },
        { label: '−5…0%', count: 74 },
        { label: '0…+5%', count: 96 },
        { label: '> +5%', count: 48 },
    ];
    const holdingByWeekday = {
        labels: ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс'],
        values: [4.2, 6.8, 3.1, 8.4, 5.6, 12.2, 9.7],
    };

    // ---- Система ----------------------------------------------
    const system = {
        cronOk: true, cronLastTickSec: 34, lastRun: '2026-07-05 12:41:26',
        botStatus: 'OK', signalsToday: 5,
    };

    // ---- Глобальные настройки ---------------------------------
    const settings = {
        allowed_symbols: 'BTC, ETH, SOL',
        scale_factor: 0.1, cooldown_seconds: 30, poll_interval_minutes: 2,
        telegram_bot_token: '7712…:AAH…q8w', telegram_chat_id: '-1001234567890', telegram_notify: 0,
        default_leverage: 3, symbol_leverage: 'BTC=5, ETH=2',
        virtual_balance: 1000, sizing_mode: 'percent_balance', sizing_fixed_usd: 50, sizing_percent: 10,
        position_min_usd: 11, position_max_usd: 0,
        fee_pct_per_side: 0.035, slippage_pct_per_side: 0.02, funding_rate_hourly_pct: 0.00125,
        partial_close_mode: 'off',
        copy_after_drawdown_enabled: 0, copy_after_drawdown_pct: 5,
        executor_mode: 'mock', executor_url: '',
        signals_retention_days: 30,
    };

    const availableTags = ['scalper', 'swing', 'degen', 'low-risk', 'btc-only'];

    // ---- Хелперы доступа --------------------------------------
    function trader(id) { return traders.find(t => t.id === id) || null; }
    function traderLabel(id) { const t = trader(id); return t ? t.label : id; }

    const totals = {
        balance: traders.reduce((s, t) => s + t.balance, 0),
        netPnl: traders.reduce((s, t) => s + t.netPnl, 0),
        trades: traders.reduce((s, t) => s + t.trades, 0),
        signals: traders.reduce((s, t) => s + t.signals, 0),
        fees: traders.reduce((s, t) => s + t.fees, 0),
        enabled: traders.filter(t => t.enabled).length,
        unrealized: positions.reduce((s, p) => s + p.pnlUsd, 0),
        posSize: positions.reduce((s, p) => s + p.sizeUsd, 0),
        wins: 152, losses: 94,
    };
    totals.winrate = +(totals.wins / (totals.wins + totals.losses) * 100).toFixed(1);

    return {
        traders, positions, watching, trades, signals, pools,
        pnlByDay, pnlByWeek, pnlByMonth, equity, bySymbol, pnlDistribution, holdingByWeekday,
        system, settings, availableTags, totals, trader, traderLabel,
    };
})();
