# 002 — ЛІНІЯ /zzlegs З НУЛЯ: детектор внутрішніх корекцій

Коротка інструкція, щоб у **новому чаті** відтворити все з нуля і рухатись далі, не
підвантажуючи попереднє листування. Тупикові гілки сюди не входять — лише те, що працює.

---

## 1. Що це за лінія

Подія — вікно 210 с. Вісім ордербук-фіч згортаються у **чотири відношення** «скільки книги
стоїть на одиницю агресії свого боку»:

| число | формула |
|---|---|
| стіна ПРОДАВЦІ | `const_resist / vol_buy` |
| приріст ПРОДАВЦІ | `(resist_plus − resist_minus) / vol_buy` |
| стіна ПОКУПЦІ | `const_support / vol_sell` |
| приріст ПОКУПЦІ | `(support_plus − support_minus) / vol_sell` |

**Внутрішня корекція** — подія всередині ноги зигзага 2.3%, яка за цими 4 числами вже
схожа на перелом, але переломом не є. Мета лінії — **детектор**: віднести подію до класу.
Прогноз майбутнього тут НЕ ставиться.

## 2. Дані

- BTC, очищений набір rev4c: **31 212 вікон** з 56 263, 14.02–08.08.2026, 175 діб.
- Множини: розворот 823 (дно 416 · вершина 407) · нога вгору 13 597 · нога вниз 15 814.
- Корекції: **2 563** у нозі вгору (18.8%) · **2 833** у нозі вниз (17.9%).
- Читається все через `zznet.load_data("BTC", with_X=False)` + кеш середніх
  `zzlegs.wmean8("BTC")` (`media/analyst/zzlegs/cache/BTC_wmean.npz`).

Передумова для ІНШОЇ монети: спершу `python3 class4.py data08 <COIN>` і `prod08 <COIN>` —
ваги BTC не переносяться.

## 3. Повний прогін з нуля

```bash
python3 zzlegs.py all BTC --force     # ~4 хв: числа, карти, таблиці вкладки
python3 zzcorr.py all BTC --force     # ~1 хв: три моделі детектора
python3 zzlegs_charts.py              # 4 англійські PNG до статті
python3 build_zzlegs_article.py       # стаття + .md (--ready щоб у чергу публікації)
node test_pages.js                    # сторож вкладок
launchctl kickstart -k gui/$UID/com.at.dashboard
```

Вкладка: **http://localhost:5058/zzlegs**. Виходи: `media/analyst/zzlegs/BTC_means.json`
(вкладка) і `BTC_corr.json` (моделі).

## 4. Як будуються корекції (щоб можна було замінити мітку)

1. Лог-регресія «розворот проти решти» на 4 числах, оцінка **поза навчанням**: 5 суцільних
   блоків часу, ембарго 30 хв. AUC **0.7474**.
2. Поріг = **медіана оцінки справжніх розворотів** (0.6258).
3. Корекція = подія ноги (не розворот) з оцінкою вище порога.

Функція `zzlegs.corrections()`. **Мітка є функцією тих самих 4 чисел** — це головне
обмеження лінії: детектор відтворює мітку, а не доводить існування класу.

## 5. Як навчаються три моделі детектора

`zzcorr.py`, три області: `up` · `dn` · `both`.

- Спліт **50/50 по часу**: 20 суцільних блоків, парні — навчання (15 606), непарні —
  валідація (15 606).
- Грід ①: сімейство (лог-регресія SGD · бустинг · мережа) × вхід (**210×4** проти 210×2).
- Грід ②: параметри переможця з кривою по епохах, береться найкраща епоха.
- Поріг підбирається **тільки на навчанні** за F1, на валідацію йде готовий.
- Метрики: **точність і повнота** (F1 лише для вибору).

Переможець в усіх трьох: **лог-регресія на 210×4**.

## 6. Контрольні числа з допусками

| що | значення | допуск |
|---|---|---|
| AUC «схоже на розворот», поза навчанням | 0.7474 | ±0.01 |
| корекцій у нозі вгору / вниз | 2 563 / 2 833 | ±30 |
| точність · повнота, модель ноги вгору (валідація) | 0.939 · 0.951 | ±0.02 |
| точність · повнота, модель ноги вниз | 0.920 · 0.939 | ±0.02 |
| точність · повнота, спільна модель | 0.935 · 0.934 | ±0.02 |
| найкращий F1 на 210×4 проти 210×2 (спільна) | 0.93 проти 0.61 | ±0.03 |
| біля дрібного перелому 0.8%: корекції / очікувано | 31.2% / 18.5% | ±1.5 п.п. |
| ліфт після зіставлення за гучністю | ×1.69 | ±0.10 |
| AUC самої гучності | 0.596 | ±0.01 |
| середній ранг корекцій усередині ноги | 0.519 / 0.523 | ±0.01 |
| перелом проти корекцій, AUC (нуль) | 0.670 (0.530) | ±0.02 |

## 7. Пастки, на яких ця лінія вже спіткнулась

1. **Усереднення.** Формула рахується ВСЕРЕДИНІ події, потім усереднюється по класу. Якщо
   зробити навпаки (сума класу / сума класу) — число інше в рази (35.62 проти 15.89), бо
   вага події стає її часткою обсягу.
2. **Гучність.** Корекції гучніші за самі розвороти (обсяг 0.514 проти 0.395). Будь-яке
   порівняння множин робити ВСЕРЕДИНІ децилів гучності, інакше міряється гучність.
3. **Ранг стирає поділ** — і це не помилка: корекції в СЕРЕДИНІ розподілу, решта ноги в
   хвостах з обох боків. Порогом «більше ніж» клас не береться.
4. **Тавтологічний контроль.** «Корекція проти решти ноги» дає AUC 0.99 — це доводить лише
   справність арифметики, бо мітка звідти й узята.
5. **Випадковий спліт заборонений** — сусіднє вікно 210 с підказує відповідь. Тільки
   суцільні блоки + ембарго.
6. **210×2 не використовувати.** Дві різниці «покупці − продавці» втрачають клас
   (F1 0.61 проти 0.93). Вони лишились на вкладці лише як ілюстрація.

## 8. Що вже перевірено і закрито (не повторювати)

- Формули `(A−B)/(A+B+1e-8)` і `ln(A+B+1)` — **виведені з лінії**: стискають хвіст, у
  якому й сидить уся різниця.
- Ноги вгору проти ніг вниз по вікнах — **не розділяються** (ARI ≈ 0, AUC 0.51–0.52).
- Сигнал корекції **не означає продовження руху**: після сигналу нозі лишається 12.6 год
  проти 16.2 у пересічної події (вгору) і 9.7 проти 16.0 (вниз).
- Бік корекції (вершина/дно) за цими 4 числами не читається: p_top 0.473 в обох ногах.

## 9. Наступні кроки

1. **Незалежна мітка.** Замінити «схоже на розворот» на мітку, не породжену цими 4 числами
   (наприклад, близькість до перелому дрібного зигзага 0.8% як ціль навчання), і
   переміряти детектор — це знімає головне обмеження лінії.
2. **П'ять інших монет.** `class4.py data08 <COIN>` + `prod08 <COIN>`, далі той самий
   ланцюг; перевірити, чи тримаються 0.93/0.95 і ліфт ×1.69.
3. **Свіжі дані після 08.08** — чи не поплив поріг.
4. **Перелом проти корекції** (зараз AUC 0.670) — єдине місце, де ще немає рішення; без
   нього детектор каже «щось відбувається», але не каже «рух закінчився».

---

Стаття лінії: `media/analyst/zzlegs/a-detector-for-corrections-inside-a-move.md`
(тема 42, `build_zzlegs_article.py`). Вкладка — `/zzlegs`, опис лінії — CLAUDE.md.
