# $QUANT — техническая документация (как это реализовано) Описание реальной реализации системы: стек, поток данных, модули, алгоритмы, формулы. Документ описывает то, что есть в коде. Термины называются как есть (rule-based, детерминированно, paper-trading) — на этой фактуре можно строить тексты без додумывания. --- ## 1. Обзор $QUANT — мульти-агентная система анализа бессрочных фьючерсов (перпов) на бирже **Hyperliquid**. Поток обработки: ``` рыночные данные (Hyperliquid API) │ ▼ теханализ (RSI, MACD, EMA, ATR, Bollinger) │ ▼ 4 стратегии-агента голосуют LONG / SHORT / SKIP │ ▼ агрегация → вердикт (направление + уверенность + размер + TP/SL) │ ├──► веб-терминал (живая отрисовка, опрос раз в ~12 c) └──► воркер: paper-trading на живых ценах + Telegram-уведомления ``` **Стек.** Фронтенд: React 19, Vite 8, TypeScript, Tailwind v4, Recharts, React Router 7, anime.js, Lenis. Воркер: Node.js + `tsx` (TypeScript-рантайм). Менеджер пакетов: pnpm. **Ключевое свойство — детерминированность.** Одно и то же состояние рынка даёт один и тот же вердикт. В торговом контуре нет генератора случайных чисел и нет LLM/ML: решение рассчитывается формулами по индикаторам. --- ## 2. Слой L1 — данные (`src/lib/hyperliquid.ts`) Источник — публичный info-API Hyperliquid: `POST https://api.hyperliquid.xyz/info`, **без авторизации**, CORS открыт (можно дёргать из браузера). Все ответы — JSON. Три запроса: | Функция | Тело запроса | Что возвращает | |---|---|---| | `getMarketStats(coins)` | `{ "type": "metaAndAssetCtxs" }` | mark/mid цена, ставка фандинга, OI, объём по каждой монете | | `getCandles(coin, interval, lookback)` | `{ "type": "candleSnapshot", "req": { coin, interval, startTime, endTime } }` | массив свечей OHLCV | | `getAllMids()` | `{ "type": "allMids" }` | средние цены по всем тикерам | **Что извлекается в `MarketStat`:** `mark` (маркировочная цена), `mid`, `prevDayPx` → из неё `changePct` (изменение за 24 ч), `funding` (часовая ставка фандинга), `openInterest` (в базовом активе) и `oiUsd = openInterest × mark`, `dayVolumeUsd`. **Свечи** (`Candle = { t, o, h, l, c, v }`): по умолчанию интервал `1h`, глубина `lookback = 120` свечей. Поддерживаемые интервалы: 1m / 5m / 15m / 1h / 4h / 1d. **Торгуемая вселенная по умолчанию:** `BTC`, `ETH`, `SOL` (константа `SYMBOLS`). Веб-терминал дополнительно показывает вкладки `BNB`, `AVAX`. Сетевой слой: таймаут 12 c через `AbortController`, при ошибке — `throw`, который выше по стеку обрабатывается (показывается последнее удачное значение / seed). --- ## 3. Слой L2 — технический анализ (`src/lib/ta.ts`) Считается из реальных свечей. Реализованные индикаторы: | Индикатор | Параметры | Реализация | |---|---|---| | **EMA** | периоды 9, 21, 50 | экспоненциальное сглаживание, `k = 2/(period+1)` | | **RSI** | период 14 | по Уайлдеру (сглаженные средние gain/loss) | | **MACD** | 12 / 26 / 9 | гистограмма = MACD-линия − сигнальная | | **ATR** | период 14 | EMA от True Range (волатильность) | | **Bollinger %B** | 20, 2σ | позиция цены в полосах: 0 = низ, 1 = верх | | **Funding-Z** | — | нормировка ставки фандинга: `clamp(funding / 0.00005, −4, 4)` (иллюстративная шкала, не статистический z-score по истории) | Функция `summarizeTA(candles, funding)` сворачивает серию в снимок `TASnapshot`: ```ts { price, rsi, ema9, ema21, ema50, emaDiffPct, // (ema9 − ema21) / price × 100 — наклон тренда macdHist, atr, atrPct, pctB, // Bollinger %B changePct, // изменение от первой свечи окна fundingZ, closes } ``` Этот снимок — единственный вход для слоя сигналов. Один и тот же `TASnapshot` всегда даёт один и тот же набор голосов. --- ## 4. Слой L3 — сигнальные агенты (`src/lib/signals.ts`) Четыре независимых rule-based стратегии. Каждая возвращает голос `Vote = { agent, layer, direction, score, reason }`, где `direction ∈ {LONG, SHORT, SKIP}`, `score ∈ 0..1` — «уверенность» (конвикция), `reason` — человекочитаемое объяснение. ### TrendAgent — следование за трендом - **LONG**, если `ema9 > ema21` и `rsi > 50`; **SHORT**, если `ema9 < ema21` и `rsi < 50`; иначе **SKIP**. - `score = clamp(|emaDiffPct| × 14 + |rsi − 50| / 60, 0, 1)`. - Пример reason: `«EMA9 above EMA21, RSI 56»`. ### BreakoutAgent — пробой полос Боллинджера - **LONG**, если `%B > 0.92`; **SHORT**, если `%B < 0.08`; иначе **SKIP**. - `score = clamp(|%B − 0.5| × 1.7, 0, 1)`. ### MeanReversionAgent — возврат к среднему (фейд крайностей) - **LONG**, если `rsi < 32` и `%B < 0.15`; **SHORT**, если `rsi > 68` и `%B > 0.85`; иначе **SKIP**. - `score` растёт по мере удаления RSI от порога. ### FundingAgent — фейд перекошенного фандинга - **SHORT**, если `funding-Z > 1.5` (лонги перегреты); **LONG**, если `funding-Z < −1.5`; иначе **SKIP**. - `score = clamp(|funding-Z| / 3, 0, 1)`. Для голосов SKIP score дополнительно занижается (×0.3–0.4) — пропуск тоже взвешивается. --- ## 5. Слой L4 — агрегация и вердикт (`src/lib/signals.ts`, `aggregate()`) Голоса сводятся в итог `Verdict`: ```ts { decision, // LONG / SHORT / SKIP confidence, // 0..1 sizePct, // рекомендуемый размер позиции, % tpPct, slPct, // take-profit / stop-loss, % reasoning, // текстовое объяснение net } // чистый счёт голосов ``` **Алгоритм:** 1. `net = Σ (±1 × score)` по всем не-SKIP голосам (LONG = +, SHORT = −). 2. `agreement` = доля голосов, совпавших со знаком `net`. 3. Порог `thr = 0.5`: `net > 0.5 → LONG`, `net < −0.5 → SHORT`, иначе `SKIP`. 4. **Уверенность:** - для сделки: `confidence = clamp(0.45 + |net|×0.18 + agreement×0.18, 0, 0.97)`; - для SKIP: `clamp(0.3 + |net|×0.2, 0.18, 0.5)`. 5. **Параметры риска** (масштабируются от волатильности `vol = clamp(atrPct, 0.4, 6)`): - `tpPct = clamp(vol × 1.6, 0.8, 6)`; - `slPct = clamp(vol × 0.9, 0.6, 3.5)`; - `sizePct = clamp(confidence × 3.2, 0.5, 3.2)`. 6. `reasoning` собирается из числа согласных агентов и причины лидирующего голоса, например: `«1/1 agents align LONG. EMA9 above EMA21, RSI 56. RR 1.9»` (RR = TP/SL). > Примечание по терминологии: в UI этот слой назван «LLMScreener / ConfidenceGate», но в > текущей реализации это **детерминированная агрегация формулами**, а не вызов LLM. > Порог уверенности (роль «ConfidenceGate») в воркере вынесен в `confFloor` (см. §6). --- ## 6. Слой L5 — paper-trading движок (`worker/paper.ts`) Превращает вердикт в **бумажную** позицию и ведёт её по реальной цене Hyperliquid. Режим жёстко `dry-run`: ордера на биржу **не подписываются и не отправляются** — это симуляция исполнения на живых рыночных данных, считающая реальный PnL. **Открытие — `maybeOpen(coin, price, verdict)`:** - пропуск, если `decision = SKIP`, или `confidence < confFloor` (по умолчанию 0.55), или по монете уже есть открытая позиция (`maxOpenPerCoin = 1`); - `entry = price` (текущая mark-цена); - `tp = entry × (1 ± tpPct/100)`, `sl = entry × (1 ∓ slPct/100)` (знак по направлению); - `notional = equity × sizePct/100 × leverage` (по умолчанию leverage = 5); - сохраняется `Position { id, coin, dir, entry, notional, tp, sl, tpPct, slPct, confidence, reason, openedAt }`. **Ведение — `markToMarket(coin, price)`:** на каждом тике, если цена пересекла TP или SL, позиция закрывается по уровню (исполнение по TP/SL предполагается точным). **Закрытие — расчёт PnL:** ``` move = (exit − entry) / entry pnlPct = (dir = LONG ? move : −move) × 100 pnlUsd = notional × pnlPct / 100 equity = equity + pnlUsd // капитал компаундируется ``` Закрытая сделка пишется в `Trade` (добавляются `exit, closedAt, pnlPct, pnlUsd, outcome ('tp'|'sl'), holdMin`). **Статистика — `stats()` (источник команды `/pnl`):** число сделок, открытые позиции, винрейт, суммарный PnL ($), ROI (%), profit factor, средний выигрыш/проигрыш, лучшая и худшая сделка, текущий капитал. --- ## 7. Слой L6 — Telegram (`worker/telegram.ts`, `worker/loop.ts`) Реализован на «голом» Bot API (без библиотек), через `fetch`. **Исходящие — `tgSend()`:** `POST .../sendMessage` с `parse_mode: HTML`. Сообщения шлются при **открытии** и **закрытии** позиции. Если токен/чат не заданы — текст печатается в stdout (воркер работает и без Telegram). Пример сообщения об открытии (реальный формат): ``` 🟢 LONG BTC-PERP @ $62,135 size 2.6% · ×5 → $1,300 notional TP +1.30% ($62,943) · SL -0.70% ($61,700) confidence 81% · 1/1 agents align LONG. EMA9 above EMA21, RSI 56. RR 1.9. ``` Пример закрытия: ``` ✅ TP BTC-PERP LONG $62,135 → $62,943 (+1.30%, +$16.90) held 2.4h · equity $10,017 ``` **Входящие — `tgPoll()`:** long-polling `getUpdates` (offset-based), раз в ~3 c. Поддерживаемые команды: `/status` (капитал, открытые позиции, винрейт), `/positions` (детально по открытым), `/pnl` (он же `/learn` — сводная статистика по закрытым сделкам), `/help`, `/start`. > Терминология: команда `/learn` в текущей реализации возвращает **статистическую сводку** > по закрытым сделкам, а не дообучение модели. --- ## 8. Воркер: рантайм (`worker/loop.ts`) Постоянный фоновый цикл — работает независимо от того, открыт сайт или нет. **Тик (`tick()`)** — по умолчанию раз в `pollMs = 60 000` мс: 1. один запрос `getMarketStats(coins)` на все монеты; 2. по каждой монете (`tickCoin`): `getCandles` → `summarizeTA` → `screen` (голоса + вердикт) → `price = mark || ta.price` → `markToMarket` (закрыть, если задело TP/SL, + уведомление) → `maybeOpen` (открыть, если есть сигнал, + уведомление) → запись в лог сигналов **при смене решения** по монете; 3. `save()` — сохранение состояния на диск. Параллельно: `commandLoop()` раз в 3 c (если задан Telegram-токен). **Запуск:** ```bash pnpm worker # бесконечный цикл pnpm worker:once # один тик и выход (смоук-тест) ``` --- ## 9. Хранение состояния (`worker/store.ts`) Один JSON-файл `worker/data/state.json` (в `.gitignore`), запись **атомарная** (во временный файл + `rename`). Переживает перезапуск. Структура `State`: ```ts { startedAt, mode, equity, // текущий капитал positions: Position[], // открытые closed: Trade[], // закрытые (последние 500) signals: SignalLog[], // лог решений при смене (последние 200) equityCurve: { t, equity }[] } // кривая капитала (последние 1000 точек) ``` Это ровно тот формат, который будущий HTTP-эндпоинт (`/api/equity`, `/api/signals`) сможет отдавать на сайт. (SQLite заменяема без изменения вызывающего кода — сейчас используется JSON.) --- ## 10. Фронтенд (`src/`) Две страницы (React Router, `src/App.tsx`): - **`/` — лендинг** (`src/pages/Landing.tsx`): секции Hero, Thesis, Layers (6-слойный конвейер), SignalDesk, AIBrief (ресёрч-агент), AgentRoster, Performance, Tokenomics, TelegramModes, Roadmap, FAQ, CTA. - **`/terminal` — живой терминал** (`src/pages/Terminal.tsx`): опрашивает Hyperliquid раз в ~12 c (`useScreen`), показывает: цену/изменение/фандинг/OI/объём/ATR, сетку индикаторов, карточку вердикта, голоса агентов с барами уверенности, граф «оркестра» агентов. **Seed-фолбэк** (`src/data/seedMarket.ts`): пока грузятся живые данные, мгновенно показываются детерминированные значения (помечены как не-live), чтобы UI не «висел»; затем заменяются реальными. **Ресёрч-агент (FactsAI)** (`src/lib/factsai.ts`, `AIBrief.tsx`): интеграция с deep-research API (AI-бриф рынка с цитатами источников). Требует прокси (CORS + ключ на сервере); секция сама скрывается, если фид недоступен. --- ## 11. Статус реализации (по слоям) Технический срез: что считается на живых данных, что симулируется, чего ещё нет. | Компонент | Статус | |---|---| | L1: свечи, mark/mid, фандинг, OI, объём | ✅ Реально (Hyperliquid live) | | L1: стакан, лента ликвидаций | ⚪ Не реализовано (только в описании ростера) | | L2: RSI / MACD / EMA / ATR / Bollinger / funding-Z | ✅ Реально | | L3: 4 агента (Trend / Breakout / MeanReversion / Funding) | ✅ Реально | | L4: агрегация → вердикт + риск-параметры | ✅ Реально (формулы, **не LLM**) | | L5: исполнение | 🟡 Paper / dry-run (реальный PnL, **без ордеров на бирже**) | | L6: Telegram (уведомления + команды) | ✅ Реально | | Персистентность | ✅ Реально (JSON; в копирайте сайта упомянут SQLite) | | Ростер «18 агентов» | ⚪ Метаданные UI; реально голосуют **4** стратегии | | Кривая капитала / «последние сделки» на сайте | 🟡 Seed-заглушка (live-данные даёт воркер, на сайт ещё не выведены) | | FactsAI ресёрч-бриф | 🟡 Код есть, **выключен** (нужен прокси; upstream отдаёт ошибку) | | Коннект кошелька / hold-to-access | ⚪ Косметика (после TGE) | | Токен $QUANT (цена/контракт/холдеры) | ⚪ pre-TGE (ещё не выпущен) | **В разработке (roadmap):** реальное исполнение ордеров на Hyperliquid (live-режим за флагом); LLM-слой (обоснование вердиктов и осмысленный `/learn` через Claude); вывод реального трек-рекорда воркера на сайт через `/api/*`. --- ## 12. Конфигурация (env, всё опционально — есть дефолты) Читается воркером из `.env.local` (`worker/config.ts`): | Переменная | Дефолт | Назначение | |---|---|---| | `QUANT_COINS` | `BTC,ETH,SOL` | торгуемая вселенная | | `QUANT_INTERVAL` | `1h` | таймфрейм свечей | | `QUANT_POLL_MS` | `60000` | период тика, мс | | `QUANT_EQUITY_START` | `10000` | стартовый бумажный капитал, $ | | `QUANT_LEVERAGE` | `5` | плечо для расчёта notional | | `QUANT_CONF_FLOOR` | `0.55` | минимальная уверенность для входа | | `QUANT_MAX_OPEN_PER_COIN` | `1` | одновременных позиций на монету | | `TELEGRAM_BOT_TOKEN` / `TELEGRAM_CHAT_ID` | — | Telegram (без них — вывод в stdout) | --- ## 13. Глоссарий - **Perp (перп)** — бессрочный фьючерс, контракт без даты экспирации. - **Hyperliquid** — децентрализованная биржа перпов с открытым публичным API данных. - **LONG / SHORT / SKIP** — ставка на рост / на падение / нет сигнала. - **Funding (фандинг)** — периодический платёж между лонгами и шортами; перекос показывает «перегретость» толпы. Положительная ставка → лонги платят шортам. - **OI (Open Interest)** — открытый интерес, сумма открытых контрактов. - **Mark price** — справедливая цена для расчётов (а не цена последней сделки). - **RSI** — осциллятор 0–100: >70 перекуплен, <30 перепродан. - **MACD** — индикатор моментума по разнице скользящих средних. - **EMA** — экспоненциальная скользящая средняя (тренд). - **ATR** — мера волатильности (средний диапазон свечи). - **Bollinger %B** — положение цены внутри полос Боллинджера (0 = низ, 1 = верх). - **TP / SL** — take-profit / stop-loss. - **RR (risk/reward)** — отношение потенциальной прибыли к риску (TP/SL). - **Notional** — номинальный размер позиции в $ (капитал × размер% × плечо). - **PnL** — прибыль/убыток. **Equity** — капитал. **Profit factor** — сумма прибылей / сумма убытков. - **Paper-trading / dry-run** — «бумажная» торговля: расчёт как в реале, но без ордеров и денег. - **Детерминированный** — при одинаковом входе всегда одинаковый результат (нет случайности). - **pre-TGE** — до выпуска токена (Token Generation Event). ```