# bot line 7.0

**Назва:** bot line 7.0

**Короткий опис:** BTC_USDT, лише купівлі. Трансформер на канві 1100 × 8
(160 год до моменту T) кожні 10 хв каже P(T у зоні дна 2.3 %); сигнал
купівлі — сума P за останні 180 хв ≥ 11.74. Тейк 2 % від найнижчої ціни
після входу, стоп 2 % від ціни входу, сигнал після закритої угоди без
підйому 2.3 % між сигналами — фейк. Режим — `paper`: бот рахує сигнал і
угоди, ордерів не шле.

Походження — дослідження 36, етапи 19–20
([`research/36-canvas600-pivots/36-canvas600-pivots.md`](../../research/36-canvas600-pivots/36-canvas600-pivots.md)):
модель — прогін `BUY_pos`, епоха 9; сигнал і правила угоди — етап 20.
Одобрено 2026-09-30.

## Як отримати бота

Сесія, якій потрібен бот, читає цей файл і бере теку `bots/bot-line-7.0/`:

| Файл | Що це |
| ---- | ----- |
| [`bot-line-7.0.md`](bot-line-7.0.md) | цей файл: опис, параметри, правила торгівлі, збірка з даних |
| [`config.json`](config.json) | усі параметри моделі, сигналу й угоди; sha256 файлів моделі |
| [`model/BUY_pos_epoch_09.pt`](model/BUY_pos_epoch_09.pt) | ваги трансформера `Future` (PyTorch `state_dict`) |
| [`model/assigner.json`](model/assigner.json) | правило кластера 2 (канал 8 канви) |
| [`bot_line_7.py`](bot_line_7.py) | запускач: `signal`, `replay`, `check` |
| [`results/replay_val.json`](results/replay_val.json) | прогін бота на val — еталон для звірки |
| [`../../tests/test_bot_line_7.py`](../../tests/test_bot_line_7.py) | тести бота |

Бот використовує модулі проєкту (розділ «Зібрати бота з даних
датаколектора» → Залежності): переносити разом із ними або запускати в
цьому проєкті. Перед роботою `bot_line_7.py` звіряє sha256 файлів моделі
з `config.json` і зупиняється, якщо вони інші.

## Параметри

| Що | Значення |
| -- | -------- |
| пара | `BTC_USDT` |
| крок моменту T | 10 хв (T кратне 600 с, кінець запису 100 с) |
| вікно канви | 160 год до T, 1100 рядків × 8 каналів |
| канали | 7 фіч `клас210х10-1х7д/д` + P(кластер 2) |
| модель | `Future`: латки по 10 рядків, dim 64, 3 шари, 4 голови, dropout 0.1, 1 логіт → sigmoid |
| вихід | P(T у зоні дна 2.3 % ноги ≥ 7 год) |
| сигнал | `S(T)` = сума P останніх 18 наявних моментів T до T включно (180 хв) |
| поріг | `S(T) ≥ θ = 11.74064453125` (квантиль 0.97 ряду `S` на val) |
| тейк | 2 % від найнижчої ціни після входу |
| стоп | 2 % від ціни входу |
| фейк | підйом 2.3 % між сигналами |
| витрати | комісія 0.05 % + сліпедж 0.02 % за бік |
| гроші | `Decimal`, старт $1000, кожна угода на всі гроші |

## Правила торгівлі

1. **Лише купівля** (довга позиція), одна позиція за раз.
2. **Вхід** — у момент T із `S(T) ≥ θ` і без відкритої позиції: купівля
   ціною open наступного запису 100 с після T (`rules/04-trading.md` →
   Бектест: виконання наступним баром).
3. **Тейк-профіт** — найнижча ціна від входу (ціна входу і close кожного
   запису 100 с після неї) × 1.02. Ціна після входу падає — тейк
   спускається за нею; росте — тейк стоїть.
4. **Стоп-лос** — ціна входу × 0.98, нерухомий. Позиція без стопу не
   відкривається (`rules/04-trading.md` → Ризик).
5. **Вихід** — перший запис 100 с, чий close дійшов до тейку чи стопу:
   продаж ціною open наступного запису.
6. **Підтвердження** — сигнали купівлі, поки позиція відкрита, нічого не
   міняють.
7. **Фейк** — позиції немає і вже була закрита угода: сигнал ігнорується,
   якщо найбільший close між попереднім сигналом (будь-яким, і під час
   угоди теж) і поточним менший за close поточного × 1.023. До першої
   угоди фейків немає.
8. **Витрати** — комісія 0.05 % і сліпедж 0.02 % на кожен бік угоди;
   результат угоди `r = (1 − 0.0007) · (продаж / купівля) · (1 − 0.0007) − 1`.

## Зібрати бота з даних датаколектора

Бот збирається з самих посекундних даних — нічого з датасетів дослідження
йому не треба.

### 1. Дані

Датаколектор (`/Users/at/projects/data_collector_candle/engine`) пише
добові CSV:

```
<root>/<рік>/<місяць>/BTC_USDT/1S_<YYYY-MM-DD>_BTC_USDT.csv
```

- Одна секунда — один рядок; дата в назві — місцева дата збирача (файл
  починається о 21:00 / 22:00 UTC попередньої доби), тому бот читає файли
  з запасом у добу з кожного боку і сам ріже секунди за `timestamp` (UTC).
- Беруться 10 колонок (`rules/scripts/data_source.py` → `SOURCE_COLUMNS`):
  `timestamp, price_avg, const_resist, resist_plus, resist_minus,
  const_support, support_plus, support_minus, vol_buy, vol_sell`; решта
  колонок збирача не читається. Дублікати `timestamp` відкидаються.
- `root` за замовчуванням — робоча копія `data/` проєкту; інша тека —
  ключем `--root` (лише читання).
- Потрібно секунд: 160 год + 1 год до першого T і до останнього T.

### 2. Хід від секунд до рішення

1. **Записи** — секунди → записи 100 с і 30 с (`bars30.bars_of_frame`):
   сума кожної колонки, open — перша `price_avg` запису, close — остання.
2. **Момент T** — кінець запису 100 с, T кратне 10 хв; T без запису, що
   кінчається рівно в T, пропускається.
3. **Канва 1100 × 7** — записи 100 с від T − 160 год до T стискаються в
   1100 рядків; на кожному рядку сім фіч `клас210х10-1х7д/д` з секунд
   рядка, нормування — лише на свою канву (`canvas1100.canvas_of`).
4. **Канал 8: P(кластер 2)** — канва 600 того самого вікна на записах 30 с
   (`canvas600_data.canvas_of`), правило кластера 1 з `model/assigner.json`
   ковзним вікном з 3 рядків (`canvas600_c1.rule_rows`, `cover`),
   P(кластер 2) = 1 − p, на рядки канви 1100 — рядок бере рядок канви 600,
   що закінчився не пізніше за нього (`canvas1100_future.rows_from`). Усе
   це — `canvas1100_buy.sample_of`.
5. **Округлення** — канва переводиться у float16 і назад (так зберігались
   канви, на яких модель вчилась і міряна).
6. **Модель** — `Future` з `model/BUY_pos_epoch_09.pt`, sigmoid логіта →
   P(T), округлена до float16 (так зберігалась видача, на якій підібрано θ;
   без цього сума на порозі зсувається на крок — вхід 24.08 04:40 замість
   04:50).
7. **Сигнал** — `S(T)` = сума P останніх 18 **наявних** моментів до T
   включно: момент без запису 100 с пропускається, а не рахується нулем
   (на val таких 94 з 5359); купівля — `S(T) ≥ 11.74064453125`. T без
   запису — сигналу немає.
8. **Угода** — правила вище (`canvas1100_buy_signal.simulate` з
   `Exits(..., trail=True)`, стоп 0.02).

### 3. Залежності

Python 3.11, `numpy`, `pandas`, `torch` (перевірено: torch 2.11.0, numpy
2.4.4, pandas 3.0.2). Модулі проєкту, які бот імпортує:

| Модуль | Що бере бот |
| ------ | ----------- |
| [`rules/scripts/data_source.py`](../../rules/scripts/data_source.py) | `load_day` — читання добового CSV |
| [`research/35-leg-fullness/scripts/bars30.py`](../../research/35-leg-fullness/scripts/bars30.py) | `day_files`, `bars_of_frame`, `read_seconds`, канва на записах |
| [`research/35-leg-fullness/scripts/classes30.py`](../../research/35-leg-fullness/scripts/classes30.py) | фічі `клас210х10-1х7д/д` |
| [`research/36-canvas600-pivots/scripts/canvas1100.py`](../../research/36-canvas600-pivots/scripts/canvas1100.py) | `canvas_of` — канва 1100 × 7 |
| [`research/36-canvas600-pivots/scripts/canvas600_data.py`](../../research/36-canvas600-pivots/scripts/canvas600_data.py), [`canvas600_c1.py`](../../research/36-canvas600-pivots/scripts/canvas600_c1.py) | канва 600 і правило кластера 1 |
| [`research/36-canvas600-pivots/scripts/canvas1100_future.py`](../../research/36-canvas600-pivots/scripts/canvas1100_future.py), [`canvas1100_future_net.py`](../../research/36-canvas600-pivots/scripts/canvas1100_future_net.py) | `rows_from`, мережа `Future` |
| [`research/36-canvas600-pivots/scripts/canvas1100_early.py`](../../research/36-canvas600-pivots/scripts/canvas1100_early.py), [`canvas1100_buy.py`](../../research/36-canvas600-pivots/scripts/canvas1100_buy.py) | `start_of`, `cluster2_rows`, `sample_of` |
| [`research/36-canvas600-pivots/scripts/canvas1100_buy_signal.py`](../../research/36-canvas600-pivots/scripts/canvas1100_buy_signal.py) | `rolling_sum`, `simulate`, `Exits`, `peaks_of` |

### 4. Команди

```bash
# сигнал у момент T (UTC, кратне 10 хв)
python3 bots/bot-line-7.0/bot_line_7.py signal --at "2026-09-15 16:00"
# бот на відрізку: P кожні 10 хв, сума, угоди, гроші
python3 bots/bot-line-7.0/bot_line_7.py replay --start "2026-08-15 00:00" --end "2026-09-21 05:00" \
    --out bots/bot-line-7.0/results/replay_val.json
# звірка P бота з видачею дослідження на val
python3 bots/bot-line-7.0/bot_line_7.py check --count 24
# з даних датаколектора напряму
python3 bots/bot-line-7.0/bot_line_7.py signal --at "2026-09-15 16:00" --root /Users/at/Desktop/DATA
# тести
python3 -m unittest discover -s tests -t tests -p "test_bot_line_7.py"
```

`signal` друкує JSON: `t`, `p` (P у T), `sum`, `theta`, `buy`, `steps`
(скільки наявних моментів у сумі). `replay` — гроші, угоди (сигнал,
вхід, вихід, ціни, причина, результат), фейки, число сигналів; `--out` —
те саме плюс P і сума на кожен T.

### 5. Перевірка, що бот зібрано правильно

- `check --count 24` — P бота проти `BUY_pos_val.npz` епохи 9 дослідження
  на 24 рівномірних T val: `max_abs_diff` 0.0, `missing` 0.
- `signal --at "2026-09-15 16:10"` — `sum` 11.98236083984375, `buy` true
  (з `--root /Users/at/Desktop/DATA` — те саме); у 16:00 — `sum`
  11.64495849609375, `buy` false.
- `replay` на val (15.08 00:00 … 21.09 05:00 UTC) — ті самі 8 угод, 32
  фейки, 158 моментів із сигналом і $1103.17, що в дослідженні 36
  (етап 20, «Результат 27»).

## Результат на val BTC

`replay` з посекундних даних, 15.08 00:00 … 21.09 05:00 UTC, 5265 моментів
T — [`results/replay_val.json`](results/replay_val.json):

| Міра | Значення |
| ---- | -------- |
| гроші | $1000 → $1103.17 (PnL +$103.17) |
| угод | 8, усі тейком, стопів 0 |
| фейків | 32 |
| моментів із сигналом | 158 |
| еталон — ідеальна торгівля купівлями по зігзагу 2.3 % | $2140.27, 12 ніг вгору; частка еталона бота 12.2 % |
| «купив і тримав» | $1366.30 |

| сигнал і вхід (UTC) | ціна входу | вихід | ціна виходу | чому | результат |
| ------------------- | ---------: | ----- | ----------: | ---- | --------: |
| 2026-08-16 02:10 | 63046.36 | 2026-08-17 15:30 | 64049.68 | тейк | 1.45 % |
| 2026-08-24 04:50 | 76950.75 | 2026-08-24 11:36 | 78367.42 | тейк | 1.70 % |
| 2026-08-28 17:00 | 77788.46 | 2026-08-30 12:33 | 78850.00 | тейк | 1.22 % |
| 2026-09-02 16:00 | 77292.01 | 2026-09-03 12:55 | 78548.72 | тейк | 1.48 % |
| 2026-09-04 14:50 | 78692.03 | 2026-09-06 23:36 | 80269.61 | тейк | 1.86 % |
| 2026-09-10 14:40 | 77251.00 | 2026-09-11 12:51 | 78041.22 | тейк | 0.88 % |
| 2026-09-11 18:10 | 77072.65 | 2026-09-14 09:51 | 78106.01 | тейк | 1.20 % |
| 2026-09-15 16:10 | 76325.79 | 2026-09-16 18:08 | 76503.78 | тейк | 0.09 % |

## Обмеження

- Параметри сигналу (вікно, θ, стоп) підібрані на тому самому val, на
  якому міряний результат: 12 ніг зігзага 2.3 %, окремого відрізка для
  перевірки немає.
- Бот проти «купив і тримав» на val програє (+$103.17 проти +$366.30):
  тейк 2 % бере малу частину довгих ніг вгору.
- `live` не вмикається: бот не шле ордерів, торгівля — лише `paper`
  (`rules/04-trading.md`).
