50 lines
6.9 KiB
Markdown
Формат **TKZ** готов: библиотека и скрипты MQL5, сжатие без потерь, распакованные данные совпадают с исходными побитово. Внутри компрессор с контекстным смешиванием (context mixing), настроенный на поток котировок. В MetaEditor код ни разу не компилировался, потому что MT5 здесь нет, так что возможны ошибки или предупреждения компиляции.
| |||
| |||
**Результаты на реальных тиках** (байт на тик, один блок на файл):
| |||
| |||
| Данные | Тиков | xz -9e по сырым записям | xz по дельтам (лучший обычный вариант) | **TKZ** |
| |||
|---|---:|---:|---:|---:|
| |||
| EURUSD, Dukascopy, ноябрь 2023 | 1,94 млн | 3,08 | 1,74 | **1,46** (−16%) |
| |||
| XAUUSD, Dukascopy, сентябрь 2023 | 2,39 млн | 2,96 | 1,69 | **1,37** (−19%) |
| |||
| XAUUSD, данные брокера, май 2026 | 0,69 млн | 3,91 | 1,91 | **1,44** (−24%) |
| |||
| US500, Tickstory, февраль 2025 | 0,20 млн | 4,93 | 2,99 | **2,20** (−26%) |
| |||
| |||
Это в 11–17 раз меньше 24-байтных записей time_msc+bid+ask и в 27–44 раза меньше `MqlTick`.
| |||
| |||
**Как устроено сжатие:**
| |||
- **Цены в целые числа.** Число знаков, шаг цены и шаг времени определяются автоматически. Для цен на грубой сетке со смещением (у XAUUSD почти все цены заканчиваются на 5) цена раскладывается по модулю 10.
| |||
- **Тик раскладывается на двоичные решения:** интервал времени, какая сторона сдвинулась, величина сдвига. Если обе стороны сдвинулись на разную величину, кодируется изменение спреда: оно предсказуемее, чем сдвиг ask.
| |||
- **Модель.** На каждое решение около 10 контекстов, двухслойный микшер и арифметический кодер. Вся арифметика целочисленная, поэтому архивы переносимы между машинами.
| |||
- **Надёжность.** Нестандартные значения (NaN, −0.0, ненормализованные цены) хранятся как есть. У каждого блока есть контрольная сумма.
| |||
| |||
Около 70% объёма у форекса занимают метки времени. Я перепробовал много вариантов, и время уже близко к своему теоретическому пределу, так что дальнейшие улучшения модели дадут единицы процентов.
| |||
| |||
**Что в репозитории** (в терминал копируется папка `MQL5`):
| |||
- `Include/Tkz/TkzCodec.mqh` — сам кодек.
| |||
- `Include/Tkz/TkzArchive.mqh` — файлы `.tkz`: запись, дозапись, чтение по блокам и по диапазону времени.
| |||
- Скрипты:
| |||
- `TkzSelfTest` — запускать первым;
| |||
- `TkzExport` — выгрузка истории в архив, блоками по дню, неделе или месяцу, с проверкой каждого блока;
| |||
- `TkzVerify` — сверка архива с историей терминала и замер скорости распаковки;
| |||
- `TkzToCustom` — загрузка архива в пользовательский символ для тестера.
| |||
- `docs/FORMAT.md` — спецификация формата, `README.md` — описание и API.
| |||
| |||
**Как проверено без MT5.** Я написал переводчик MQL5→C++ и эмуляцию среды MQL5 с проверкой выхода за границы массивов, поэтому тестируется тот же самый код:
| |||
- все 5,2 млн реальных тиков восстанавливаются побитово;
| |||
- граничные случаи: пустой блок, NaN/Inf, отрицательное время, отрицательные цены, сетка 0,25;
| |||
- 3000 испорченных блоков: каждый либо отклонён, либо восстановлен точно, падений нет;
| |||
- все четыре скрипта прогнаны целиком на эмулированном терминале.
| |||
| |||
**Что прошу сделать у себя:**
| |||
1. **Компиляция.** Я писал на осторожном подмножестве MQL5 и вычитывал код вручную. Если MetaEditor выдаст ошибки или предупреждения, пришлите лог, поправлю.
| |||
2. **Запустите `TkzSelfTest`.** Все строки должны быть `PASS`. Главная — `golden output`: она сравнивает байты с эталонной сборкой, и `FAIL` в ней значит, что MQL5 где-то считает иначе.
| |||
3. **Скорость.** Её в MQL5 я измерить не мог. C++-сборка того же кода делает около 250 тыс. тиков/с и на сжатие, и на распаковку; в MQL5, вероятно, будет медленнее. Реальные цифры напечатают `TkzSelfTest` и `TkzExport`. Если окажется слишком медленно, могу сделать быстрый режим с меньшим числом контекстов ценой пары процентов сжатия.
| |||
| |||
**Ограничения:**
| |||
- Хранятся только time_msc, bid и ask. При распаковке флаги BID/ASK восстанавливаются там, где значение изменилось; `last` и объёмы равны нулю.
| |||
- Размер блока влияет на сжатие: месяц практически оптимален, неделя хуже на 0,2%, день на 1%.
| |||
| |||
Всё закоммичено в `main` (13 коммитов). Push не делал, потому что remote ещё нет. Тестовые данные в репозиторий не входят; их скачивает `tests/data/fetch_samples.sh`. Источник Dukascopy блокирует автоматическую загрузку (отвечает 429), поэтому взял их копии с Hugging Face:
| |||
- [Henrik404/dukascopy-ticks](https://huggingface.co/datasets/Henrik404/dukascopy-ticks)
| |||
- [CarlosSilva1/xauusd-ticks](https://huggingface.co/datasets/CarlosSilva1/xauusd-ticks)
| |||
- [CarlosSilva1/us500-ticks](https://huggingface.co/datasets/CarlosSilva1/us500-ticks)
|