English
preview
Фундаментальные предобученные модели в трейдинге: прогнозирование временных рядов с TimesFM 2.5 от Google в MetaTrader 5

Фундаментальные предобученные модели в трейдинге: прогнозирование временных рядов с TimesFM 2.5 от Google в MetaTrader 5

MetaTrader 5Индикаторы |
182 3
Seyedsoroush Abtahiforooshani
Seyedsoroush Abtahiforooshani

В области обработки естественного языка мы наблюдали смену парадигмы: большие фундаментальные предобученные модели, обученные на огромных корпусах и затем адаптированные к конкретным задачам, вытеснили подход обучения с нуля. Возникает естественный вопрос: может ли эта революция трансферного обучения работать для временных рядов?

Google Research ответила на этот вопрос утвердительно, представив TimesFM (Time Series Foundation Model) в статье «Фундаментальная модель с декодерной архитектурой для прогнозирования временных рядов», принятой на ICML 2024. TimesFM — это трансформер с декодерной архитектурой на 200 миллионов параметров, предобученный на 100 миллиардах реальных временных точек. Несмотря на то что он значительно меньше современных LLM, он демонстрирует высокое качество прогнозирования в режиме zero-shot в разных предметных областях и на разных уровнях гранулярности. Во многих случаях он достигает результатов на уровне моделей, обученных на целевых наборах данных, или превосходит их.

Это особенно полезно для алгоритмического трейдинга, поскольку модель можно дообучать на собственных финансовых данных. Используя PEFT с адаптерами LoRA, мы можем специализировать TimesFM под конкретные инструменты, сохраняя число обучаемых параметров ниже 100 тыс. Это помогает снизить переобучение на нестационарных рыночных данных.

В этой статье мы создаем полный сквозной конвейер, который:

  1. Экспортирует данные OHLCV из MetaTrader 5 для 14 инструментов (валютные пары, индексы, сырьевые товары)
  2. Формирует богатый набор ковариат, включающий фазы Луны, события экономического календаря, торговые сессии и технические признаки
  3. Дообучает TimesFM 2.5 с адаптерами LoRA на этих финансовых данных
  4. Генерирует вероятностные прогнозы с квантильными оценками (10-й, 50-й и 90-й процентили)
  5. Экспортирует прогнозы обратно в MetaTrader 5 в виде CSV-файлов
  6. Визуализирует прогнозы прямо на графике с помощью пользовательского индикатора MQL5 с доверительными полосами

Полная кодовая база Python (папка mt5) приложена к статье в виде ZIP-архива. Базовую библиотеку TimesFM необходимо клонировать из официального репозитория GitHub.


Архитектура TimesFM: Концепция

Перед тем как перейти к деталям реализации, кратко рассмотрим ключевые идеи TimesFM, которые делают эту модель пригодной для финансовых временных рядов.

Трансформер с декодерной архитектурой для временных рядов

LLM обычно используют декодерную архитектуру: текст токенизируется, токены проходят через стек каузальных слоев трансформера, и каждая выходная позиция предсказывает следующий токен. TimesFM применяет тот же принцип к временным рядам, но с важной адаптацией: вместо текстовых токенов модель работает с патчами — непрерывными группами временных точек.

При длине входного патча 32 и длине выходного патча 128 модель одновременно учится:

  • Использовать первые 32 точки для прогноза следующих 128
  • Использовать первые 64 точки для прогноза точек 65–192
  • Использовать первые 96 точек для прогноза точек 97–224
  • И так далее...

Такая стратегия повышает эффективность инференса. Например, прогноз 256 точек из контекста длиной 256 требует 2 шага генерации вместо 8, что уменьшает накопление ошибок.

Входной ряд (512 точек)
  ┌────────────────────────────────────────────┐
  │ patch_1 │ patch_2 │ ... │ patch_16         │
  └────────────────────────────────────────────┘
        │           │               │
        ▼           ▼               ▼
  ┌─────────────────────────────────────┐
  │    Стек каузальных трансформеров       │
  │    (слои самовнимания + FFN)    │
  └─────────────────────────────────────┘
        │           │               │
        ▼           ▼               ▼
  ┌────────────────────────────────────────────┐
  │ forecast_1 │ forecast_2 │ ... │ forecast_N │
  └────────────────────────────────────────────┘

Данные предобучения

TimesFM 2.5 предобучена на:

  • GiftEvalPretrain — отобранной коллекции временных рядов от Salesforce
  • Wikimedia Pageviews — данных веб-трафика, отражающих реальные тренды и сезонность
  • Google Trends — данных поискового интереса, отражающих макроэкономические и культурные циклы
  • Синтетических и аугментированных данных — обучающих модель «грамматике» временных закономерностей

Такое разнообразное предобучение означает, что модель уже понимает такие понятия, как тренды, сезонность, сдвиги уровней и кластеризация волатильности, еще до того, как увидит хотя бы одну финансовую свечу.

Почему дообучать, а не обучать с нуля?

Финансовые временные ряды создают уникальную проблему: объем пригодных данных ограничен (рынки открыты примерно 252 дня в году), а сами данные по природе нестационарны. Обучение глубокой модели с нуля на наших 14 инструментах практически гарантировало бы переобучение.

LoRA (Low-Rank Adaptation) элегантно решает эту проблему. Вместо обновления всех 200 млн параметров мы внедряем небольшие обучаемые низкоранговые матрицы только в последние 2 из 20 слоев трансформера. Это дает примерно 102 тыс. обучаемых параметров — соотношение объема данных и числа параметров остается приемлемым даже при нашем относительно небольшом наборе данных. Предобученные представления в первых 18 слоях обобщаются гораздо лучше, чем все, что мы могли бы выучить из ограниченных финансовых данных.

Ковариаты: больше, чем просто исходные цены

Ключевая возможность TimesFM 2.5 — поддержка внешних ковариат через механизм xreg. Наш конвейер использует это, подавая в модель:

Группа ковариат Признаки Обоснование
Циклические временные hour_sin/cos, dow_sin/cos, woy_sin/cos, moy_sin/cos, dom_sin/cos Рынки демонстрируют выраженную внутридневную и недельную сезонность
Рыночные сессии session_tokyo, session_london, session_ny, session_overlap Режимы волатильности и ликвидности меняются вместе с торговыми сессиями
Фазы Луны phase_sin/cos, is_new_moon, is_full_moon, days_to_new, days_to_full Эмпирически изученная корреляция с рыночными настроениями
Экономический календарь econ_FOMC, econ_NFP, econ_CPI_US, econ_GDP_US, days_to_event Крупные макроэкономические события вызывают смену режимов
Технические прокси atr_norm, volume_norm, spread_norm, returns_1h/4h/24h Контекст недавней волатильности и моментума

Все временные признаки используют циклическое кодирование sin/cos, чтобы избежать разрывов на границах периодов — это устоявшаяся практика моделирования временных рядов.


Архитектура проекта

Конвейер организован как набор модульных Python-скриптов в папке mt5/ и управляется из единой точки входа:

mt5/
├── config.py                         # Все пути, инструменты, гиперпараметры
├── run_pipeline.py                   # Оркестратор: последовательно запускает шаги 17
├── .env                              # Учетные данные MT5 + ключ API FRED
├── scripts/
│   ├── export_mt5_data.py           # Шаг 1: загрузка OHLCV из MetaTrader 5
│   ├── generate_moon_phases.py      # Шаг 2: астрономические расчеты фаз Луны
│   ├── generate_economic_calendar.py # Шаг 3: FRED API + даты FOMC
│   ├── build_covariates.py          # Шаг 4: объединение всех признаков
│   ├── finetune.py                  # Шаг 5: дообучение LoRA/DoRA
│   ├── forecast.py                  # Шаг 6: генерация вероятностных прогнозов
│   ├── export_to_mt5.py            # Шаг 7: запись CSV в MQL5/Files/
│   └── visualize_forecast.py       # Опционально: HTML-панель прогнозов
├── mql5/
│   └── TimesFM_Forecast.mq5        # Индикатор графика для MetaTrader 5
├── checkpoints/                     # Сохраненные веса адаптера LoRA
└── data/
    ├── mt5_exports/                 # Исходные CSV-файлы OHLCV
    ├── moon_phases/                 # Предварительно вычисленные лунные данные
    ├── economic_calendar/           # Данные событий FRED + FOMC
    ├── covariates/                  # Итоговые объединенные наборы данных
    └── forecast_results.json        # Полный результат прогноза

Каждый скрипт самодостаточен и может запускаться отдельно, но оркестратор run_pipeline.py связывает их вместе:

python mt5/run_pipeline.py                  # Полный конвейер (шаги 1–7)
python mt5/run_pipeline.py --skip-finetune  # Повторно использовать существующий адаптер
python mt5/run_pipeline.py --from-step 4    # Возобновить с этапа ковариат
python mt5/run_pipeline.py --only 6 7       # Только прогноз + экспорт


Установка и настройка

Клонирование репозитория TimesFM

TimesFM версии 2.5 пока недоступна через pip install из PyPI. Клонируйте официальный репозиторий:

git clone https://github.com/google-research/timesfm.git 
cd timesfm

Установка зависимостей

Рекомендуемый подход использует uv для быстрого разрешения зависимостей:

# Установить TimesFM в editable-режиме с поддержкой torch и ковариат
uv pip install -e ".[torch,xreg]"

# Дополнительные зависимости для конвейера MT5
pip install ephem MetaTrader5 python-dotenv plotly fredapi

Для систем без uv:

pip install -e ".[torch,xreg]"
pip install ephem MetaTrader5 python-dotenv plotly fredapi

Примечание по оборудованию: Дообучение выполняется на любом CUDA GPU. Скрипт автоматически обнаруживает GPU NVIDIA, Intel XPU/NPU и при необходимости переходит на CPU. Для конфигурации по умолчанию (batch_size=128, context=512, bf16) рекомендуется GPU NVIDIA с 8+ ГБ VRAM. Обучение на CPU работает, но значительно медленнее.

Извлечение папки mt5

Скачайте mt5.zip, приложенный к статье, и распакуйте его в корень репозитория так, чтобы папка mt5/ находилась рядом с src/, peft/ и tests/:

timesfm/
├── mt5/            ← извлечено из приложения
├── peft/
├── src/
├── tests/
├── pyproject.toml
└── ...

Настройка учетных данных

Создайте (или отредактируйте) файл mt5/.env с учетными данными MetaTrader 5 и ключом FRED API:

# Учетная запись MetaTrader 5
MT5_LOGIN=12345678
MT5_PASSWORD=your_password
MT5_SERVER=YourBroker-Server

# API FRED Федеральной резервной системы (бесплатно: https://fred.stlouisfed.org/docs/api/api_key.html)
FRED_API_KEY=your_fred_api_key

Учетные данные MetaTrader 5 нужны для шагов 1 и 7 (экспорт данных и экспорт прогнозов). Ключ FRED API требуется только для шага 3 (генерация экономического календаря).

Настройка инструментов

Все инструменты определены в mt5/config.py. Конфигурация по умолчанию охватывает 14 символов в трех классах активов:

INSTRUMENTS = {
    "DJ30":    {"mt5_symbol": "DJ30",      "asset_class": "index",     "base_currency": "USD"},
    "NAS100":  {"mt5_symbol": "NAS100",    "asset_class": "index",     "base_currency": "USD"},
    "XAUUSD":  {"mt5_symbol": "XAUUSD.i",  "asset_class": "commodity", "base_currency": "USD"},
    "WTI":     {"mt5_symbol": "WTI",       "asset_class": "commodity", "base_currency": "USD"},
    "EURUSD":  {"mt5_symbol": "EURUSD.i",  "asset_class": "forex",    "base_currency": "EUR"},
    "USDJPY":  {"mt5_symbol": "USDJPY.i",  "asset_class": "forex",    "base_currency": "USD"},
    "GBPUSD":  {"mt5_symbol": "GBPUSD.i",  "asset_class": "forex",    "base_currency": "GBP"},
    "AUDUSD":  {"mt5_symbol": "AUDUSD.i",  "asset_class": "forex",    "base_currency": "AUD"},
    "USDCAD":  {"mt5_symbol": "USDCAD.i",  "asset_class": "forex",    "base_currency": "USD"},
    "USDCHF":  {"mt5_symbol": "USDCHF.i",  "asset_class": "forex",    "base_currency": "USD"},
    "NZDUSD":  {"mt5_symbol": "NZDUSD.i",  "asset_class": "forex",    "base_currency": "NZD"},
    "EURGBP":  {"mt5_symbol": "EURGBP.i",  "asset_class": "forex",    "base_currency": "EUR"},
    "EURJPY":  {"mt5_symbol": "EURJPY.i",  "asset_class": "forex",    "base_currency": "EUR"},
    "GBPJPY":  {"mt5_symbol": "GBPJPY.i",  "asset_class": "forex",    "base_currency": "GBP"},
}

Настройте значения mt5_symbol в соответствии с правилами именования вашего брокера. Некоторые брокеры используют суффиксы вроде .i, .pro или m — проверьте панель «Обзор рынка» в терминале MetaTrader 5.


Реализация: Шаг за шагом

Шаг 1. Экспорт данных OHLCV из MetaTrader 5

Скрипт export_mt5_data.py подключается к запущенному терминалу MetaTrader 5 через пакет MetaTrader 5 для Python и загружает исторические данные OHLCV для всех настроенных инструментов.

def export_instrument(name: str, info: dict) -> pd.DataFrame | None:
    symbol = info["mt5_symbol"]

    if not mt5.symbol_select(symbol, True):
        print(f"  ПРЕДУПРЕЖДЕНИЕ: символ {symbol} недоступен в MT5. Пропуск.")
        return None

    tf_const = getattr(mt5, TIMEFRAME, None)
    rates = mt5.copy_rates_from_pos(symbol, tf_const, 0, BARS_TO_PULL)

    if rates is None or len(rates) == 0:
        return None

    df = pd.DataFrame(rates)
    df["datetime"] = pd.to_datetime(df["time"], unit="s")
    df = df[["datetime", "open", "high", "low", "close", "tick_volume", "spread"]]
    return df.sort_values("datetime").reset_index(drop=True)

Параметр BARS_TO_PULL (по умолчанию 50 000) управляет объемом истории, загружаемой по каждому символу. Для таймфрейма H1 50 000 баров покрывают примерно 8 лет рыночных данных — достаточно для дообучения.

Скрипт записывает по одному CSV на инструмент в mt5/data/mt5_exports/ :

EURUSD_H1.csv XAUUSD_H1.csv DJ30_H1.csv ...

Важно: Перед выполнением этого шага терминал MetaTrader 5 должен быть запущен, а вход в счет — выполнен.

python mt5/scripts/export_mt5_data.py

Шаги 2–3. Генерация статических наборов признаков

Два скрипта предварительно вычисляют наборы данных, независимые от рыночных данных; их нужно сгенерировать только один раз.

Фазы Луны

Скрипт generate_moon_phases.py использует астрономическую библиотеку ephem (PyEphem) для точного расчета данных о фазах Луны с часовым разрешением с 2000 по 2026 год:

def build_hourly_moon_data(start: str, end: str) -> pd.DataFrame:
    dt_range = pd.date_range(start=start, end=end, freq="h")
    records = []

    for dt in dt_range:
        m = ephem.Moon()
        m.compute(dt.strftime("%Y/%m/%d %H:%M:%S"))
        phase_pct = float(m.phase) / 100.0  # 0=new, ~1=full
        records.append({"datetime": dt, "phase_pct": phase_pct})

    df = pd.DataFrame(records)
    df["phase_sin"] = np.sin(2 * np.pi * df["phase_pct"])
    df["phase_cos"] = np.cos(2 * np.pi * df["phase_pct"])
    # ... binary flags for new/full/quarter + days_to_next
    return df

Лунный цикл был предметом эмпирических исследований на финансовых рынках. Независимо от того, является ли эффект реальным или случайным совпадением, включение его как ковариаты позволяет модели самой определить его значимость во время обучения.

Экономический календарь

Скрипт generate_economic_calendar.py получает фактические даты публикации основных экономических индикаторов США из REST API Federal Reserve Economic Data (FRED):

  • CPI (индекс потребительских цен) — высокая важность
  • PPI (индекс цен производителей) — средняя важность
  • GDP (валовой внутренний продукт) — высокая важность
  • NFP (занятость вне сельского хозяйства) — высокая важность
  • Розничные продажи — средняя важность
  • Заседания FOMC — взяты с сайта Федеральной резервной системы (все даты 2000–2026 жестко заданы из официального календаря)

Каждое событие становится бинарным признаком с часовым разрешением, а также признаком days_to_event, который формирует эффект нарастающего ожидания по мере приближения события.

python mt5/scripts/generate_moon_phases.py
python mt5/scripts/generate_economic_calendar.py

Шаг 4. Построение объединенных ковариат

Скрипт build_covariates.py объединяет все данные в один DataFrame для каждого инструмента:

OHLCV data   ─┐
Moon phases  ─┤
Econ calendar ┼──→ merge on datetime ──→ add time features ──→ EURUSD_H1_covariates.csv
Sessions     ─┤
Technical    ─┘

Объединение выполняется по временным меткам, округленным до часа. Временные признаки вычисляются динамически:

def add_time_features(df: pd.DataFrame) -> pd.DataFrame:
    dt = df["datetime"]

    # Циклическое кодирование помогает избежать разрывов
    df["hour_sin"] = np.sin(2 * np.pi * dt.dt.hour / 24).astype(np.float32)
    df["hour_cos"] = np.cos(2 * np.pi * dt.dt.hour / 24).astype(np.float32)

    df["dow_sin"]  = np.sin(2 * np.pi * dt.dt.dayofweek / 7).astype(np.float32)
    df["dow_cos"]  = np.cos(2 * np.pi * dt.dt.dayofweek / 7).astype(np.float32)

    # ... week of year, month of year, day of month
    return df

Рыночные сессии кодируются бинарными флагами на основе диапазонов часов UTC, определенных в config.py. Перекрытие Лондона и Нью-Йорка — известное максимальной ликвидностью и волатильностью на форексе — получает отдельный флаг.

Технические прокси (ATR, объем, спред) нормализуются с использованием 24-часового скользящего среднего, чтобы сделать их инвариантными к масштабу разных инструментов.

python mt5/scripts/build_covariates.py

На выходе формируется один полный CSV-файл на инструмент в mt5/data/covariates/; каждый файл содержит более 40 столбцов признаков.

Шаг 5. Дообучение TimesFM с помощью LoRA

Это ядро конвейера. Скрипт finetune.py загружает предобученную модель TimesFM 2.5 с HuggingFace и применяет дообучение LoRA с помощью фреймворка PEFT, включенного в репозиторий.

Обнаружение оборудования

Скрипт начинается с автоматического обнаружения оборудования: определяются CUDA GPU, Intel XPU (Arc) и устройства NPU:

def detect_hardware():
    if torch.cuda.is_available():
        for i in range(torch.cuda.device_count()):
            props = torch.cuda.get_device_properties(i)
            vram_gb = props.total_memory / (1024 ** 3)
            print(f"  CUDA:{i}  {props.name}  ({vram_gb:.1f} GB VRAM)")
    # ... Intel XPU, NPU detection ...
    # Выбрать лучший GPU или перейти на CPU

Обоснование гиперпараметров

Каждый гиперпараметр обучения в config.py намеренно подобран с прицелом на сохранение капитала в реальной торговле. Этот раздел объясняет обоснование, поскольку такие настройки отличаются от типичной практики глубокого обучения:

CONTEXT_LEN         = 512     # 512 часовых баров ≈ 21 торговый день
HORIZON_LEN         = 48      # Горизонт 48 часов = примерно 2 торговых дня
BATCH_SIZE          = 128     # Увеличенный размер батча стабилизирует оценку градиента
NUM_EPOCHS          = 100     # Максимальный предел; ранняя остановка обычно завершает обучение раньше
ADAPTER_TYPE        = "lora"  # Оставляет около 100 тыс. обучаемых параметров
LORA_RANK           = 4       # Минимальный практически полезный ранг
LORA_ALPHA          = 8.0     # alpha/rank = 2.0 (типичное масштабирование LoRA)
LORA_DROPOUT        = 0.15    # Снижает риск запоминания ценовых шаблонов
NUM_ADAPTER_LAYERS  = 2       # Адаптируются только 2 последних слоя из 20
LEARNING_RATE       = 5e-5    # Осторожный шаг обучения: финансовые данные дают шумную функцию потерь
WEIGHT_DECAY        = 0.1     # Выраженная L2-регуляризация
WARMUP_RATIO        = 0.15    # Линейный разогрев на 15%, чтобы избежать резких скачков градиента
EARLY_STOPPING_PATIENCE = 15  # Валидационная ошибка на финансовых данных нестабильна — требуется запас терпения

LORA_RANK = 4 заслуживает особого внимания. При 14 инструментах и примерно 638 тыс. баров данных соотношение данных к параметрам должно оставаться высоким. Ранг 4 дает около 102 тыс. обучаемых параметров в 2 слоях — достаточно, чтобы выучить доменно-специфические поправки, но недостаточно, чтобы запоминать шум.

NUM_ADAPTER_LAYERS = 2 означает, что мы адаптируем только последние 10% стека трансформера. Логика в том, что ранние слои кодируют общие временные закономерности (тренды, сезонность, сдвиги уровней), которые хорошо переносятся между доменами. Только поздние слои нуждаются в настройке для распознавания финансово-специфических закономерностей.

Цикл обучения

Модель загружается и адаптируется:

model_wrapper = timesfm.TimesFM_2p5_200M_torch.from_pretrained(
    "google/timesfm-2.5-200m-pytorch",
    torch_compile=False,  # Нужно отключить для дообучения
)

config = PEFTConfig(
    adapter_type="lora",
    lora_rank=4,
    lora_alpha=8.0,
    lora_dropout=0.15,
    num_adapter_layers=2,
    # ... other parameters
)

trainer = PEFTTrainer(model_wrapper.model, config)
history = trainer.fit(train_ds, val_ds)

Данные делятся хронологически (80/20), чтобы предотвратить заглядывание в будущее. Для финансовых данных это критично. Обучающие окна используют 50% перекрытие для разнообразия:

for s in all_series:
    split_idx = int(len(s) * 0.8)
    train_series.append(s[:split_idx])
    val_series.append(s[split_idx:])

Веса адаптера сохраняются в формате SafeTensors в mt5/checkpoints/. Лучший чекпойнт (по валидационной потере) сохраняется как best_adapter.safetensors, также сохраняются чекпойнты по эпохам.

python mt5/scripts/finetune.py
# Или с пользовательскими параметрами:
python mt5/scripts/finetune.py --adapter_type dora --num_epochs 30 --lora_rank 8

Шаг 6. Генерация прогнозов

Скрипт forecast.py загружает дообученную модель и генерирует вероятностные прогнозы для всех инструментов:

# Загрузить базовую модель
model_wrapper = timesfm.TimesFM_2p5_200M_torch.from_pretrained(
    "google/timesfm-2.5-200m-pytorch", torch_compile=True
)

# Подключить адаптер LoRA и загрузить дообученные веса
peft_config = PEFTConfig(lora_rank=LORA_RANK, lora_alpha=LORA_ALPHA, ...)
inject_adapters(model_wrapper.model, peft_config)
load_adapter_weights(model_wrapper.model, adapter_path)

Для каждого инструмента скрипт:

  1. Загружает последние CONTEXT_LEN баров цен закрытия из CSV с ковариатами
  2. Строит будущие ковариаты для горизонта прогноза (временные признаки вычисляются точно; технические признаки заполняются вперед; экономические события обнуляются для неизвестного будущего)
  3. Вызывает метод модели forecast_with_covariates
point, quantiles = model.forecast_with_covariates(
    inputs=[close_context],
    dynamic_numerical_covariates=dynamic_numerical,
    static_categorical_covariates={
        "asset_class": [asset_class],
        "instrument": [name],
    },
    xreg_mode="xreg + timesfm",
)

Настройка xreg_mode="xreg + timesfm" означает, что модель объединяет свое внутреннее представление временного ряда с внешней информацией ковариат — сочетая преимущества обоих подходов.

Выход сохраняется в mt5/data/forecast_results.json и содержит для каждого инструмента:

  • Точечный прогноз (среднее)
  • 10-й процентиль (q10) — нижняя доверительная граница
  • 50-й процентиль (q50) — медиана
  • 90-й процентиль (q90) — верхняя доверительная граница
  • Последняя цена закрытия и дата/время для справки
python mt5/scripts/forecast.py
# Для одного инструмента:
python mt5/scripts/forecast.py --instrument XAUUSD --horizon 48
# Без дообученного адаптера (только базовая модель):
python mt5/scripts/forecast.py --no_adapter

Шаг 7. Экспорт в MetaTrader 5

Скрипт export_to_mt5.py записывает CSV-прогнозы по каждому инструменту в каталог терминала MetaTrader 5 MQL5/Files/TimesFM/:

def find_mt5_files_dir() -> Path:
    """Auto-detect MT5 terminal's MQL5/Files directory."""
    if mt5 is not None:
        if mt5.initialize():
            info = mt5.terminal_info()
            files_dir = Path(info.data_path) / "MQL5" / "Files"
            mt5.shutdown()
            return files_dir
    # Резервный вариант: просканировать AppData/Roaming/MetaQuotes/Terminal/
    ...

Формат CSV разработан так, чтобы индикатор MQL5 легко его разбирал:

datetime,point,q10,q50,q90
2026.04.08 14:00,1.0842,1.0831,1.0841,1.0853
2026.04.08 15:00,1.0845,1.0830,1.0844,1.0860
...

Также записывается файл временной метки last_update.txt, чтобы индикатор мог показывать, когда прогноз был обновлен в последний раз. 

Выполните следующую команду: python mt5/scripts/export_to_mt5.py

sample of the indicator and how it looks



Индикатор MQL5

Индикатор TimesFM_Forecast.mq5 читает CSV-файлы, созданные на шаге 7, и отображает прогноз непосредственно на графике MetaTrader 5. В отличие от стандартных индикаторов, использующих индикаторные буферы, он рисует графические объекты — это необходимо, поскольку прогноз строится на будущие бары, за пределами последнего сформированного бара.

Структура

Индикатор создает четыре визуальных элемента:

  1. Линия точечного прогноза — сплошные трендовые линии зеленого (бычий) или красного (медвежий) цвета в зависимости от направления от последнего закрытия к конечной точке прогноза
  2. 90% доверительная полоса — заполненные треугольники между линиями квантилей q10 и q90, дающие визуальную оценку неопределенности
  3. Линия медианы (q50) — пунктирная белая линия, показывающая медианный прогноз
  4. Опорная линия — пунктирная горизонтальная линия на уровне последней цены закрытия для удобного сравнения

Загрузка CSV

Функция LoadForecastCSV() разбирает файл прогноза построчно:

bool LoadForecastCSV()
{
   string filename = InpSubfolder + "\\" + g_symbol + "_forecast.csv";
   int handle = FileOpen(filename, FILE_READ | FILE_CSV | FILE_ANSI, ',');
   if(handle == INVALID_HANDLE)
      return false;

   // Пропустить заголовок
   while(!FileIsLineEnding(handle) && !FileIsEnding(handle))
      FileReadString(handle);

   // Считать строки данных в массивы
   while(!FileIsEnding(handle))
   {
      string dt_str = FileReadString(handle);
      string pt_str = FileReadString(handle);
      string q10_str = FileReadString(handle);
      string q50_str = FileReadString(handle);
      string q90_str = FileReadString(handle);
      // ... преобразовать и сохранить в глобальные массивы
   }
   FileClose(handle);
   return true;
}

Отрисовка прогноза

Доверительная полоса отображается как пары заполненных треугольников для каждого сегмента между соседними точками прогноза:

for(int i = 0; i < g_horizon - 1; i++)
{
   datetime t1 = g_forecast_times[i];
   datetime t2 = g_forecast_times[i+1];

   // Triangle 1: upper-left, upper-right, lower-left
   CreateBandTriangle(OBJ_PREFIX + "band1_" + IntegerToString(i),
      t1, g_q90[i],  t2, g_q90[i+1],  t1, g_q10[i],  InpBandColor);

   // Triangle 2: upper-right, lower-right, lower-left
   CreateBandTriangle(OBJ_PREFIX + "band2_" + IntegerToString(i),
      t2, g_q90[i+1],  t2, g_q10[i+1],  t1, g_q10[i],  InpBandColor);
}

Каждый четырехугольник (между двумя временными точками) разбивается на два треугольника, потому что тип MQL5 OBJ_TRIANGLE поддерживает только три опорные точки.

В левом верхнем углу отображается метка направления с сигналом прогноза, процентным изменением, горизонтом и временем последнего обновления:

TimesFM: LONG +0.42% | 48h | обновлено: 2026.04.0813:00:00

Автоперезагрузка

Индикатор автоматически перезагружает CSV на каждом новом баре (если включен InpAutoReload), а также поддерживает ручную перезагрузку по нажатию клавиши R:

void OnChartEvent(const int id, const long &lparam,
                  const double &dparam, const string &sparam)
{
   if(id == CHARTEVENT_KEYDOWN && lparam == 'R')
   {
      if(LoadForecastCSV())
      {
         g_loaded = true;
         DrawForecast();
      }
   }
}

Установка

Скопируйте файл индикатора в каталог данных MetaTrader 5:

  1. Откройте MetaTrader 5
  2. Перейдите в Файл → Открыть каталог данных
  3. Перейдите в MQL5/Indicators/
  4. Скопируйте TimesFM_Forecast.mq5 в эту папку
  5. В панели «Навигатор» щелкните правой кнопкой по ИндикаторамОбновить
  6. Скомпилируйте индикатор (дважды щелкните, чтобы открыть его в MetaEditor, затем нажмите F7)
  7. Перетащите индикатор на любой график, для символа которого есть CSV с прогнозом
Входные параметры
Параметр По умолчанию Описание
InpBullColor Lime Цвет линий бычьего прогноза
InpBearColor Tomato Цвет линий медвежьего прогноза
InpBandColor DodgerBlue Цвет заливки доверительной полосы
InpMedianColor White Цвет линии медианы (q50)
InpForecastWidth 3 Толщина линии прогноза
InpBandWidth 1 Толщина границ полосы
InpAutoReload true Перезагружать прогноз на каждом новом баре
InpSubfolder "TimesFM" Имя подпапки в MQL5/Files/


Панель визуализации

Для тех, кто предпочитает анализировать все инструменты сразу вне MetaTrader 5, скрипт visualize_forecast.py генерирует интерактивную HTML-панель с помощью Plotly:

python mt5/scripts/visualize_forecast.py
# Пользовательское окно истории:
python mt5/scripts/visualize_forecast.py --history 120 --output my_dashboard.html

Панель показывает:

  • Недавнюю историю цен (серым) для каждого инструмента
  • Точечный прогноз с цветовой индикацией направления
  • 90% доверительную полосу в виде заполненной области
  • Горизонтальную опорную линию на уровне последнего закрытия
  • Сводную таблицу, ранжирующую инструменты по «уверенности» — отношению ожидаемого движения к ширине неопределенности

Результат сохраняется в mt5/data/forecast_dashboard.html и может быть открыт в любом браузере.


Запуск полного конвейера

После установки и настройки полный конвейер можно выполнить одной командой:

python mt5/run_pipeline.py

Это последовательно запускает все 7 шагов:

Шаг 1/7: экспорт OHLCV из MetaTrader 5
Шаг 2/7: генерация признаков фаз Луны
Шаг 3/7: генерация экономического календаря
Шаг 4/7: построение объединенных ковариат
Шаг 5/7: дообучение TimesFM (LoRA)
Шаг 6/7: прогноз по всем инструментам
Шаг 7/7: экспорт прогнозов в MT5

Полезные сокращения рабочего процесса:

# Пропустить дообучение (использовать существующий адаптер)
python mt5/run_pipeline.py --skip-finetune

# Пропустить фазы Луны (они не меняются)
python mt5/run_pipeline.py --skip-moon

# Запустить только прогноз и экспорт (после подготовки данных)
python mt5/run_pipeline.py --only 6 7

# Возобновить с построения ковариат (например, после добавления нового инструмента)
python mt5/run_pipeline.py --from-step 4


Практические соображения

Защита от переобучения

Финансовые данные особенно сложны для машинного обучения: отношение сигнал/шум крайне низкое, а базовый процесс нестационарен. Наш конвейер использует несколько уровней защиты:

  1. Минимальная емкость адаптера — ранг LoRA 4 только с 2 адаптированными слоями (102 тыс. параметров против 200 млн замороженных)
  2. Хронологическое разделение на обучающую и валидационную выборки — без утечки данных из будущего в прошлое
  3. Сильная регуляризация — weight decay 0.1 + dropout LoRA 0.15
  4. Ранняя остановка — прекращает обучение, когда валидационная потеря перестает улучшаться (patience = 15)
  5. Консервативная скорость обучения — 5e-5 с 15% линейным разогревом

Когда переобучать

Адаптер следует переобучать, когда:

  • Накопились значимые новые данные (каждые несколько недель для таймфрейма H1)
  • Видимо изменился рыночный режим (например, переход от низкой к высокой волатильности)
  • Точность прогнозов заметно ухудшается

Конвейер делает это простым: запустите python mt5/run_pipeline.py --from-step 1, чтобы загрузить свежие данные и переобучить модель.

Ограничения
  • Не самостоятельный торговый сигнал. Прогнозы следует сочетать с управлением рисками, расчетом размера позиции и подтверждением другими методами анализа
  • Качество прогноза ухудшается с ростом горизонта. Горизонт по умолчанию 48 баров (2 дня) уже агрессивен для финансовых данных. Более длинные горизонты следует рассматривать с меньшей уверенностью
  • Прогнозирование ковариат вперед является приближенным. Будущие значения технических признаков (ATR, объем) заполняются вперед от последнего известного значения, что является упрощением
  • Задержка. Python-конвейер не предназначен для высокочастотной торговли. Он рассчитан на внутридневной таймфрейм (H1) или выше


Заключение

В этой статье мы построили полноценный мост между фундаментальной моделью Google TimesFM 2.5 и MetaTrader 5. Ключевые элементы системы включают:

  • Экспорт данных из MetaTrader 5 по 14 инструментам из форекса, индексов и сырьевых товаров
  • Богатую инженерию ковариат, включающую астрономические данные, макроэкономические события, рыночные сессии и технические признаки
  • Параметрически эффективное дообучение с помощью адаптеров LoRA, тщательно настроенных для предотвращения переобучения на нестационарных финансовых данных
  • Вероятностное прогнозирование с квантильными оценками, формирующими полосы неопределенности
  • Двунаправленную интеграцию с MetaTrader 5 — данные выходят из MetaTrader 5 для обучения и возвращаются обратно для визуализации на графике

Предобученная модель TimesFM уже улавливает временные закономерности, усвоенные на 100 миллиардах точек данных, а адаптация LoRA специализирует эти знания для финансовых рынков с минимальным риском переобучения. Индикатор MQL5 дает визуальную обратную связь прямо в торговом терминале, что делает прогнозы пригодными для практического использования.

Эта работа показывает, что фундаментальные предобученные модели, изначально разработанные для естественного языка, можно эффективно адаптировать для финансовых временных рядов при сочетании с правильными стратегиями дообучения и доменно-специфической инженерией признаков. По мере роста возможностей таких моделей разрыв между качеством в режиме zero-shot и качеством обучения с учителем, вероятно, будет сокращаться, делая трансферное обучение все более практичным инструментом в арсенале алгоритмического трейдера.


Список источников
  1. А. Дас, У. Конг, А. Лич, С. К. Матур, Р. Сен, Р. Юй. «Фундаментальная модель с декодерной архитектурой для прогнозирования временных рядов», ICML 2024
  2. Репозиторий TimesFM на GitHub — Google Research
  3. Модель TimesFM 2.5 200M PyTorch — HuggingFace
  4. Блог Google Research: модель с декодерной архитектурой для прогнозирования временных рядов
  5. TimesFM в BigQuery ML — Google Cloud Documentation
  6. Э. Дж. Ху и др. "LoRA: низкоранговая адаптация больших языковых моделей", ICLR 2022
  7. Ю. Не и др. "Временной ряд стоит 64 слова: долгосрочное прогнозирование с трансформерами" (PatchTST)
Программы, использованные в статье
# Файл Тип Описание
1 config.py Конфигурация Все пути, инструменты, гиперпараметры и значения по умолчанию
2 run_pipeline.py Оркестратор Запускает полный 7-шаговый конвейер с управлением через CLI
3 export_mt5_data.py Скрипт Экспортирует данные OHLCV из MetaTrader 5
4 generate_moon_phases.py Скрипт Вычисляет фазы Луны по часам с помощью PyEphem
5 generate_economic_calendar.py Скрипт Получает даты экономических событий из FRED API
6 build_covariates.py Скрипт Объединяет все признаки в CSV по каждому инструменту
7 finetune.py Скрипт Дообучает TimesFM 2.5 с адаптерами LoRA/DoRA
8 forecast.py Скрипт Генерирует вероятностные прогнозы для всех инструментов
9 export_to_mt5.py Скрипт Записывает CSV-прогнозы в каталог MQL5/Files/
10 visualize_forecast.py Скрипт Генерирует интерактивную HTML-панель прогнозов
11 TimesFM_Forecast.mq5 Индикатор Графический индикатор MQL5, отображающий прогноз с доверительными полосами

Все Python-скрипты находятся в mt5/scripts/. Индикатор MQL5 находится в mt5/mql5. Полная папка mt5/ доступна как ZIP-файл для скачивания, приложенный к этой статье.

Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/22096

Прикрепленные файлы |
mt5.zip (43.65 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (3)
Stanislav Korotky
Stanislav Korotky | 21 апр. 2026 в 14:18

Я не специалист в этой области, поэтому непонятно, как вы подаете векторы с 40+ признаками в TimesFM, который якобы является одномерным (1 признак на точку)? Это скрыто за патчами или адаптерами? Ни то, ни другое в статье не раскрывается.

Также, если я правильно понимаю, вы обучаете и прогнозируете каждый инструмент независимо. Будет ли целесообразнее подавать все признаки для всех инструментов, чтобы прогнозировать будущий горизонт каждого инструмента? Рынок - это целая система, где каждый инструмент влияет на другие.

Seyedsoroush Abtahiforooshani
Seyedsoroush Abtahiforooshani | 6 мая 2026 в 22:22
Stanislav Korotky #:

Я не специалист в этой области, поэтому непонятно, как вы подаете векторы с 40+ признаками в TimesFM, который якобы является одномерным (1 признак на точку)? Это скрыто за патчами или адаптерами? Ни то, ни другое в статье не раскрывается.

Также, если я правильно понимаю, вы обучаете и прогнозируете каждый инструмент независимо. Будет ли целесообразнее подавать все признаки для всех инструментов, чтобы прогнозировать будущий горизонт каждого инструмента? Рынок - это целая система, где каждый инструмент влияет на другие.

Настоящее совместное мультиинструментальное прогнозирование - это другая модель (например, PatchTST или Moirai с перемешиванием каналов, или TFT с кросс-серийными статическими вкраплениями), а не TimesFM. В рамках ограничений TimesFM практическим компромиссом является "добавить доходности других инструментов в качестве ковариаты" и смириться с тем, что вы слабо отражаете связь.

Вы правы, что ядро TimesFM одномерное - трансформатор токенизирует патчи одной серии. 40+ функций не входят через путь патчей. Они вводятся через отдельный механизм xreg (внешние регрессоры) в TimesFM 2.5, который в статье упоминается в вызове forecast_with_covariates:

.
point, quantiles = model.forecast_with_covariates(
    inputs=[close_context],                       # одномерный ряд
    dynamic_numerical_covariates=dynamic_numerical, # 40+ функций
    static_categorical_covariates={...},
    xreg_mode="xreg + timesfm",
)


Таким образом, существует два параллельных пути:

  • Собственно TimesFM видит только близкие серии, патченные и пропущенные через трансформатор декодера, как и было задумано.
  • Путь xreg берет ковариаты и настраивает отдельный компонент регрессии (в реализации xreg в TimesFM это, по сути, линейная/ридж-модель над ковариатами, настраиваемая на контекстное окно).

Настройка xreg_mode="xreg + timesfm" объединяет эти два компонента: TimesFM прогнозирует остаток после компонента xreg, или оба прогноза комбинируются аддитивно (в зависимости от режима). Это не патч, и это не адаптеры в смысле LoRA - адаптеры здесь используются только для тонкой настройки весов трансформатора TimesFM, совершенно отдельно от того, как потребляются ковариаты.
Mustafa Umarella Alfaridzi
Mustafa Umarella Alfaridzi | 8 мая 2026 в 23:40
Здравствуйте, я заметил, что библиотека PEFT не доступна в реализации, показанной в этой статье. совместима ли HF PEFT с этой статьей?
Разработка инструментария для анализа Price Action (Часть 50): Создание модуля согласования сигналов RVGI, CCI и SMA на MQL5 Разработка инструментария для анализа Price Action (Часть 50): Создание модуля согласования сигналов RVGI, CCI и SMA на MQL5
Многим трейдерам сложно распознавать настоящие развороты. В этой статье представлен советник, который объединяет RVGI, CCI (±100) и трендовый фильтр SMA, формируя единый четкий сигнал разворота. Советник включает панель на графике, настраиваемые алерты и полный исходный файл, готовый к немедленной загрузке и тестированию.
Нейросети в трейдинге: Принятие торговых решений с учётом неопределённости (Оценка неопределённости) Нейросети в трейдинге: Принятие торговых решений с учётом неопределённости (Оценка неопределённости)
В статье продолжена адаптация фреймворка UncAD для задач алгоритмического трейдинга. Реализованы объект распределения рыночных состояний и энкодер неопределённости, формирующий совместное представление состояния рынка и степени доверия к нему. Предложенная архитектура позволяет модели учитывать не только структуру рыночного режима, но и устойчивость собственной интерпретации, что особенно важно в условиях нестационарности финансовых рынков.
Разработка динамического мультивалютного советника (Часть 5): Скальпинг и свинг-трейдинг Разработка динамического мультивалютного советника (Часть 5): Скальпинг и свинг-трейдинг
В этой части рассматривается, как разработать динамический мультивалютный советник, способный адаптироваться к режимам скальпинга и свинг-трейдинга. В ней рассматриваются структурные и алгоритмические различия в генерации сигналов, исполнении сделок и управлении рисками, благодаря которым советник может гибко переключаться между стратегиями в зависимости от рыночного поведения и входных параметров.
Разработка инструментария для анализа Price Action (Часть 49): Интеграция индикаторов тренда, моментума и волатильности в единую систему на MQL5 Разработка инструментария для анализа Price Action (Часть 49): Интеграция индикаторов тренда, моментума и волатильности в единую систему на MQL5
Упростите графики MetaTrader 5 с помощью советника Multi Indicator Handler. Этот интерактивный инструмент объединяет индикаторы тренда, моментума и волатильности в единую панель, работающую в реальном времени. Мгновенно переключайтесь между профилями, чтобы сосредоточиться на нужном вам типе анализа. Одним кликом скрывайте и показывайте элементы панели и сохраняйте фокус на движении цены. Читайте дальше, чтобы шаг за шагом узнать, как самостоятельно создать и настроить этот инструмент на MQL5.