Бот статистического арбитража фьючерсов на природный газ между Московской биржей (RTSX) и NYMEX (XNYM).
Создан в рамках туториала на Хабре: Как написать алготрейдинг-бота с помощью ИИ-агента
Торгует в рамках соревнования алгостратегий Finam Arena.
Стратегия эксплуатирует временное расхождение цен между идентичными по сроку фьючерсами на газ на двух биржах.
Спред = цена_RTSX − цена_XNYM
Z-score = (спред − mean) / std [скользящее окно, 25 000 точек ≈ 30 дней M1]
| Условие | Действие |
|---|---|
|z| > 2.0 |
Открыть позицию: купить недооценённый, продать переоценённый |
|z| < 0.5 |
Закрыть позицию (конвергенция) |
|z| > 3.5 |
Стоп-лосс |
Рероллинг контрактов происходит автоматически за 5 торговых дней до экспирации — по расписанию из data/ng/ng_pairs_2026.json.
Finam gRPC (SubscribeQuote)
│ real-time тики
▼
Rolling deque ──► Z-score ──► Signal
(2000 точек) │
▼
Arena REST API
POST /v1/accounts/{id}/orders
| Компонент | Назначение |
|---|---|
main.py |
Стратегия: z-score, сигналы, рероллинг, P&L |
arena.py |
REST-клиент Finam Arena с авто-обновлением JWT |
scripts/download_ng_history.py |
Загрузка M1-истории из Finam API |
scripts/backtest.py |
Бэктест на исторических M1-данных |
data/ng/ng_pairs_2026.json |
Календарь контрактов RTSX ↔ XNYM на 2026 год |
data/ng/contracts/*_m1.csv |
Поконтрактные M1-данные; пополняются ежедневно из живого стрима |
1. Скопируй .env.example в .env и заполни:
cp .env.example .env# Finam Trade API — для gRPC котировок
FINAM_API_KEY=your_finam_api_key_here
# Finam Arena — для исполнения ордеров
ARENA_API_TOKEN=your_arena_api_token_here
ARENA_ACCOUNT_ID=1000000FINAM_API_KEY— токен на api.finam.ru/docs/tokensARENA_API_TOKENиARENA_ACCOUNT_ID— в личном кабинете arena.finam.ru
2. Загрузи исторические данные (один раз):
uv run python scripts/download_ng_history.py3. (Опционально) Запусти бэктест:
uv run python scripts/backtest.py
uv run python scripts/backtest.py --start 2026-06-01 --end 2026-06-22
uv run python scripts/backtest.py --start 2026-06-01 --end 2026-06-22 --json signals.json4. Запусти стратегию:
uv run python main.pyЗапускать из директории arbitrage/. Celery не нужен — standalone async процесс.
Все параметры — константы в начале main.py:
| Параметр | Значение | Описание |
|---|---|---|
DEPOSIT |
1 000 000 RUB | База для расчёта размера позиции |
Z_OPEN |
2.0 | Порог открытия |
Z_CLOSE |
0.5 | Порог закрытия (конвергенция) |
Z_STOP |
3.5 | Стоп-лосс |
SPREAD_WINDOW |
25 000 | Размер скользящего окна (точек, ~30 дней M1) |
WARMUP_MIN_POINTS |
30 | Минимум точек для начала торговли |
LOOKBACK_DAYS |
30 | Дней истории для прогрева при старте |
SAMPLE_SEC |
5 | Интервал между оценками сигнала (сек) |
STALE_QUOTE_SEC |
30 | Макс. возраст котировки (сек) |
ROLL_DAYS_BEFORE |
5 | Торговых дней до экспирации для рероллинга |
COMM_RTSX / COMM_XNYM |
0.001% / 0.1% | Комиссия по биржам |
2026-06-19 10:15:32 INFO NG Arbitrage starting
Deposit=1,000,000 Z_open=2.0 Z_close=0.5 Z_stop=3.5
Quotes: Finam gRPC | Orders: Arena REST (account=1000001)
2026-06-19 10:15:33 INFO Active pair NGM6@RTSX ↔ NGN26@XNYM
2026-06-19 10:15:33 INFO Warmup loaded: 1847 spread samples from last 30 days
2026-06-19 10:15:33 INFO Subscribing quotes: ['NGM6@RTSX', 'NGN26@XNYM']
2026-06-19 11:03:17 INFO ┌─ OPEN SHORT_SPREAD SELL NGM6@RTSX / BUY NGN26@XNYM z=+2.143 qty=48
2026-06-19 11:03:17 INFO Arena SIDE_SELL NGM6@RTSX ×48 price=4.3120 comm=0.0021
2026-06-19 11:03:17 INFO Arena SIDE_BUY NGN26@XNYM ×48 price=4.2980 comm=2.0630
2026-06-19 11:03:17 INFO │ RTSX=4.3120 XNYM=4.2980 spread=0.0140
2026-06-19 11:03:17 INFO │ capital=413280.00 entry_comm=2.0651
2026-06-19 14:22:51 INFO └─ CLOSE [CONVERGE] z=+0.312
2026-06-19 14:22:51 INFO SHORT_SPREAD held=3:19:34
2026-06-19 14:22:51 INFO RTSX 4.3120→4.2940 XNYM 4.2980→4.2770
2026-06-19 14:22:51 INFO spread 0.0140→0.0170
2026-06-19 14:22:51 INFO gross=+0.0144 comm=4.1302 net=-4.1158 trade_ret=-0.0100%
2026-06-19 14:22:51 INFO ═══ total_pnl=-4.1158 total_ret=-0.0010% trades=1 (W0/L1)
Стратегия написана с использованием Claude Code и finam-skill — расширения для работы с Finam Trade API из Claude Code — по следующим промптам.
Стратегия арбитража фьючерсов на природный газ между российской и американской биржой.
Текущая пара: NGM6@RTSX (Мосбиржа) и NGN26@XNYM (NYMEX) — оба активны в июне 2026.
Используя finam skill, найди тикеры фьючерсов за весь 2026 год (январь–декабрь) на
обеих биржах. Тикеры имеют закономерности в названиях:
- Для российской биржи (RTSX): поле name имеет вид NG-{n}.26, где n — номер месяца
- Для американской (XNYM): тикер имеет вид NG*26, где * — буква, обозначающая месяц
Сопоставь контракты в пары по месяцам экспирации. Правило маппинга неизвестно заранее —
выведи его самостоятельно на основе данного примера и дат экспирации контрактов из API.
По контрактам, чья дата экспирации уже прошла на момент запуска скрипта, выгрузи
исторические минутные данные за период активной торговли каждого контракта.
Склей данные всех контрактов каждой биржи в одну непрерывную временну́ю серию —
отдельный файл для RTSX и отдельный для XNYM. В каждом файле должна быть колонка
contract с тикером источника. Сохрани в data/ng/.
/trade-api
Используй @old/ng_pair_grpc_min_capital.py как референс архитектуры.
Стратегия арбитража фьючерсов на природный газ между российской и американской биржой:
NGM6@RTSX (Мосбиржа) и NGN26@XNYM (NYMEX) (июнь).
Нужно предусмотреть рероллинг на другой месяц после даты экспирации. Для этого используй
маппинг по месяцам в @data/ng/ng_pairs_2026.json.
Размер депозита: 1 млн рублей. Не принимай во внимание валюты и лотность. Торгуй
насколько позволяет капитал. Цены приведены к одной базе.
Z-score: засей deque(2000) из последних 30 дней CSV, добавляй каждый сэмпл в реальном
времени. Сэмплируй раз в 5 сек. Пропускай сэмпл если котировка любой ноги старше 30 сек.
Сигналы:
- Открывай позицию если |z| > 2: покупай недооценённый, продавай переоценённый
- Закрывай позицию если |z| < 0.5 (конвергенция)
- Стоп-лосс: закрывай если |z| > 3.5
P&L считай через спред: (spread_exit - spread_entry) * pos_dir * qty.
Трекай wins/losses отдельно. База для % — реально задействованный капитал.
Транслируй сделки в консоль вместе с рассчитанной доходностью и общей доходностью.
Комиссия: RTSX 0.001%, XNYM 0.1% от суммы ордера.
Используй SubscribeQuote (gRPC) для котировок в реальном времени.
Реконнект при обрыве, SIGINT/SIGTERM → финальная сводка.
Ежедневно аппендь M1-бары (агрегированные из тиков) в CSV.
Загрузка ключей из .env.
Рероллинг: за 5 торговых дней до экспирации автоматически переходи на следующий месяц.
Используй данные из @data/ng/ng_rtsx_m1_continuous.csv и
@data/ng/ng_xnym_m1_continuous.csv для расчёта исторического z-score за последние 30 дней.
Реализуй открытие и закрытие сделок через платформу соревнований алгостратегий Finam Arena.
Вот документация: https://arena.finam.ru/docs
Вынеси функции в отдельный файл.