Алексей Боровков
Алгоритмический трейдинг: Создание, тестирование и запуск роботов на рынке Форекс

Часть 1: Основы автоматической торговли.

Глава 1: Введение в алгоритмический трейдинг на Форексе. Эра машин

Представьте себе идеального трейдера. Он никогда не спит, не ест, не отвлекается на новости или эмоции. Он молниеносно анализирует терабайты данных, неукоснительно соблюдает риск-менеджмент и совершает сделки в точно рассчитанный момент, 24 часа в сутки, 7 дней в неделю. Этот трейдер – не сверхчеловек. Это торговый робот, или советник (Expert Advisor), воплощающий в себе суть алгоритмической торговли.

Алгоритмический трейдинг (алготрейдинг) – это использование компьютерных программ, которые следуют четко заданному набору правил (алгоритму) для автоматического открытия, управления и закрытия торговых позиций на финансовых рынках. На Форексе, где ликвидность огромна, а движения часто вызваны математическими закономерностями, алготрейдинг нашел свою идеальную среду.

Переход от субъективного человеческого решения к объективному машинному исполнению – это революция. Но как у любой революции, у нее есть две стороны: мощные преимущества и скрытые опасности.

Плюсы: Почему мир переходит на алгоритмы

1. Скорость и точность исполнения. Человеческая реакция измеряется долями секунды, машинная – микро- и наносекундами. Робот может отследить сигнал на десятке пар одновременно, мгновенно рассчитать объем позиции согласно риск-менеджменту и выставить ордер без задержек. Это критично для стратегий скальпинга и торговли на новостях, где цена может пройти нужное расстояние быстрее, чем вы моргнете.

2. Железная дисциплина. Главный враг трейдера – эмоции: жадность, заставляющая держать убыточную сделку, и страх, заставляющий рано закрыть прибыльную. Робот лишен психологии. Он будет снова и again открывать сделки по системе, даже если предыдущие 5 раз закрылись в убыток. Он строго соблюдает правила мани-менеджмента, никогда не «доливается» в убыток на эмоциях.

3. Возможность глубокого тестирования (Backtesting). Это самый мощный аргумент. Прежде чем рисковать реальными деньгами, вы можете «прогнать» стратегию робота на многолетних исторических данных. Как система вела себя в кризис 2008 года? Как на выборах в США? Ответы даст backtesting. Он позволяет количественно оценить ключевые метрики: общую прибыль, максимальную просадку, риск-ривард, процент прибыльных сделок. Вы можете оптимизировать параметры, подбирая наилучшие для конкретного инструмента и периода.

4. Масштабируемость и многозадачность. Один алгоритм может торговать на сотнях символов, одновременно отслеживая корреляции и глобальные рыночные условия. Человек физически не способен на такой охват.

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

Минусы: Подводные камни автоматизации

1. Риск переоптимизации (Кривая подгонка). Это бич алготрейдинга. Используя возможности тестера, можно так «настроить» параметры робота (периоды индикаторов, уровни стоп-лосса) под конкретный исторический период, что он покажет на графике прибыли невероятную красоту. Но такая стратегия «подогнана» под шум прошлых данных и абсолютно беспомощна в реальных, будущих условиях. Она работает идеально только на истории. Это как ключ, идеально отточенный под один замок, который больше не встретится.

2. Технические сбои и риски. Ваш идеальный трейдер полностью зависит от технологий. Разрыв интернет-соединения, отказ сервера брокера (VPS), сбой в подаче электричества, ошибка в коде при нестандартных рыночных условиях (например, «шпилька» на графике) – все это может привести к незакрытой позиции, убыткам или пропущенной прибыли. Ответственность за техническую инфраструктуру (резервный канал связи, надежный VPS) лежит на вас.

3. Отсутствие гибкости и интуиции. Робот слепо следует алгоритму. Он не понимает контекста. Он не отличит панику на рынке из-за геополитического кризиса от обычной технической коррекции. Он не прочитает между строк выступление главы ЦБ и не учтет «настроение рынка». В периоды фундаментальных потрясений, когда логика рушится, жесткая алгоритмическая система может нанести убытки, тогда как живой трейдер смог бы вовремя выйти из рынка.

4. Дрейф рынка (Изменение волатильности и закономерностей). Рынки эволюционируют. Закономерности, работавшие в условиях низкой волатильности и QE (количественного смягчения), могут перестать работать при росте ставок и высокой волатильности. Робот, настроенный на старые условия, будет продолжать торговать, пока не «сольет» счет. Алгоритм требует периодического мониторинга и адаптации.

5. Ложное чувство безопасности и «перекладывание ответственности». Начинающие алготрейдеры часто впадают в заблуждение: «Робот все сделает за меня, можно не следить». Это прямая дорога к потере депозита. Автоматизация не отменяет необходимости понимать логику стратегии, следить за ее работой и управлять рисками. Робот – это ваш инструмент, а не черный ящик, приносящий деньги.

Вывод главы:

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

Робот – идеальный солдат, но генералом стратегии должны оставаться вы. Осознание как силы, так и ограничений автоматизации – это первый и самый важный шаг на пути к созданию устойчивой алгоритмической торговли. В следующих главах мы разберемся, как создаются эти «солдаты» и как превратить сырую идею в отлаженную торговую машину.

Глава 2: Техническая база: Инструменты алготрейдера

Если торговый робот – это «идеальный солдат», то платформа для его создания и развертывания – это целый арсенал, полигон и командный пункт. Выбор технологического стека определяет, насколько мощным, гибким и надежным будет ваш автоматический трейдинг. Давайте разберемся с фундаментом.

Торговые платформы: Где живут роботы

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

1. MetaTrader 4 / MetaTrader 5: Индустриальный стандарт

Подавляющее большинство розничных трейдеров начинают и часто остаются в экосистеме MetaTrader от компании MetaQuotes.

· MetaTrader 4 (MT4): Легенда рынка. Создан в 2005 году, ориентирован прежде всего на Форекс и CFD. Его главные преимущества – невероятная распространенность, стабильность, огромное сообщество и тонны готовых индикаторов, скриптов и советников. Однако его архитектура начинает устаревать: нет мультитрединга, ограниченные возможности тестирования (только на одном ядре), устаревший язык MQL4.

· MetaTrader 5 (MT5): Эволюционное, но не полное, замещение MT4. Выпущен в 2010 году. Это более мощная и современная платформа:

· Больше рынков: Форекс, фьючерсы, акции, криптовалюты.

· Улучшенный тестер стратегий: Многопоточное тестирование и оптимизация, использование облачных ресурсов брокера.

· Больше типов ордеров: Неттинговая система учета позиций (как на биржах), помимо хеджирования (как в MT4).

· Встроенный экономический календарь и чат.

· Современный язык MQL5.

Почему начинают с MT4/5? Готовая экосистема, минимальные требования к знаниям программирования для запуска готовых роботов, поддержка практически у любого форекс-брокера.

2. Python + Библиотеки: Царство гибкости и мощи

Если MetaTrader – это удобный заводской автомобиль, то Python – это мастерская, где вы можете собрать свой гоночный болид с нуля.

· Python: Универсальный язык программирования, ставший де-факто стандартом для анализа данных, машинного обучения и, как следствие, для профессионального алготрейдинга.

· Библиотеки:

· backtrader, zipline – фреймворки для бэктестинга стратегий.

· pandas, numpy – для молниеносной обработки и анализа данных (котировок).

· scikit-learn, TensorFlow, PyTorch – для внедрения машинного обучения и нейросетей.

· ccxt – единый API для подключения к сотням криптобирж и некоторым форекс-брокерам.

· MetaTrader5 (пакет для Python) – для подключения к терминалу MT5 и управления им прямо из кода на Python.

Преимущества Python:

· Неограниченная гибкость: Вы можете реализовать любую, самую сложную логику, интегрировать внешние данные (например, сеты новостей через API), использовать передовые методы ИИ.

· Лучшие возможности тестирования: Глубокий анализ результатов, кастомные метрики, Walk-Forward анализ.

· Контроль над всем: От подключения к брокеру до управления рисками.

Недостатки:

· Высокий порог входа: нужно уверенно знать Python.

· Нужно самостоятельно решать вопросы надежности исполнения, логирования, развертывания на сервере (VPS).

· Прямое подключение к брокерам может быть сложнее, чем через MT.

Советник (Expert Advisor, EA): Сердце системы

Советник (Expert Advisor, EA) – это и есть торговый робот в экосистеме MetaTrader. Это программа, написанная на языке MQL4/MQL5, которая работает внутри терминала MT4/MT5.

Как это работает?

1. Вы устанавливаете файл советника (*.ex4 для MT4, *.ex5 для MT5) в терминал.

2. Прикрепляете его к графику конкретной валютной пары (например, EURUSD).

3. Советник начинает свою работу в реальном времени. Он:

· Слушает поток котировок.

· Анализирует данные на основе заложенного алгоритма (проверяет условия индикаторов, цену и т.д.).

· Принимает решение: если условия для входа/выхода выполнены, он автоматически отправляет торговый приказ (ордер) на сервер брокера через терминал.

4. Он работает непрерывно, пока вы не отключите его или не закроете терминал.

Важно: Советник работает на вашем компьютере или VPS. Он зависит от вашего подключения к интернету и работы терминала.

Языки MQL4 и MQL5: На чем говорят советники

Чтобы создать своего робота для MetaTrader, нужно выучить его родной язык.

MQL4: Язык для MT4

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

· Ориентирован на процедурное программирование (хотя ОПП тоже возможно).

· Ограниченная скорость тестирования.

· Устаревающий, но еще живой стандарт. Огромное наследие в виде тысяч бесплатных и платных советников.

MQL5: Современный язык для MT5

· Мощнее и современнее. Полноценная поддержка объектно-ориентированного программирования (ООП), что позволяет создавать более сложные, модульные и поддерживаемые советники.

· Гораздо больше встроенных функций для работы с графикой, файлами, сетевыми запросами (WebRequest), что позволяет, например, отправлять уведомления в Telegram.

· Прямой доступ к историческим данным и инструментам технического анализа без необходимости вручную рассчитывать индикаторы.

· Высокая скорость выполнения и тестирования благодаря компиляции в native-код и многопоточности.

Простой пример для иллюстрации различий:

Задача: Открыть рыночный ордер на покупку 0.1 лота по текущей цене.

На MQL4 (упрощенно):

```cpp

int ticket = OrderSend(Symbol(), OP_BUY, 0.1, Ask, 3, 0, 0, "My EA Comment", 12345, 0, clrGreen);

```

На MQL5 (используя торговые классы):

```cpp

CTrade trade;

trade.Buy(0.1, _Symbol, 0, 0, 0, "My EA Comment");

```

Код MQL5 часто более структурированный и читаемый для сложных проектов.

-–

Вывод главы:

Выбор технической базы – стратегическое решение.

· Новичкам, которые хотят быстро начать и тестировать классические стратегии, стоит выбрать MetaTrader 5 (или MT4, если брокер не поддерживает MT5) и изучать MQL5 (он перспективнее).

· Профессионалам и энтузиастам данных, стремящимся к максимальной гибкости, сложным стратегиям с ИИ и полному контролю, – прямая дорога к Python и соответствующим библиотекам.

· Советник (EA) – это исполнительный механизм в терминале MetaTrader, преобразующий ваш алгоритм в конкретные торговые приказы.

Помните: ни одна платформа не отменяет необходимости понимать логику торговли. Дальше мы погрузимся в этапы создания и, что критически важно, проверки жизнеспособности вашего будущего робота.

Глава 3: Жизненный цикл торгового робота: От идеи до машины

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

Давайте пройдем весь путь.

Этап 1: ИДЕЯ – Зарождение гипотезы

Все начинается не с кода, а с рыночной гипотезы. Это четкое, проверяемое утверждение о поведении цены.

· Что это такое? "Когда 20-периодная SMA пересекает 50-периодную SMA снизу вверх на дневном графике, а RSI > 50, то цена с вероятностью выше 55% продолжит рост в ближайшие 5 дней".

· Источники идей:

· Классические книги по техническому анализу (Элдер, Мерфи, Нисон).

· Академические исследования (статьи о сезонности, корреляциях).

· Наблюдение за графиками и выявление повторяющихся паттернов.

· Адаптация известных стратегий (например, "Черепахи") под Форекс.

· Критерий хорошей идеи: Она должна быть конкретной, формализуемой и статистически проверяемой. Идея "покупать, когда цена низкая" – плохая. Идея "покупать, когда цена опускается на 1.5 стандартных отклонения ниже 100-дневной скользящей средней" – хорошая.

Этап 2: РАЗРАБОТКА – Воплощение в код

Здесь гипотеза превращается в алгоритм. Это самый технический этап.

1. Формализация правил: Распишите идею до мельчайших деталей, как инструкцию для самого примитивного робота.

· Условие ВХОДА (лонг): (SMA(20) > SMA(50)) && (RSI(14) > 50) && (Цена закрытия > SMA(20)).

· Условие ВЫХОДА (тейк-профит/стоп-лосс): Фиксированный в пунктах? Динамический (например, на уровне ATR)? По обратному сигналу?

· Правила управления капиталом: Риск на сделку (например, 1% от депозита). Фиксированный лот или переменный?

· Фильтры: Время торговли (исключить азиатскую сессию? выходные?), макрособытия (выход Non-Farm Payrolls).

2. Написание кода: Используя выбранную платформу (MQL5/Python), вы программируете все правила. На этом этапе важна чистота кода и логирование (запись всех действий и решений робота в файл для последующего разбора).

Этап 3: ТЕСТИРОВАНИЕ – Суровая проверка реальностью

Это самый важный и многоступенчатый этап, цель которого – не подтвердить гениальность идеи, а обнаружить ее слабые места.

1. Бэктестинг (Backtest) – Испытание историей.

· Что это? Прогонка алгоритма на исторических данных за несколько лет. Платформа эмулирует, как робот торговал бы в прошлом.

· Цель: Получить первичную статистику и отсеять заведомо убыточные идеи. 80% идей погибают здесь.

· Ключевые метрики:

· Общая прибыль и кривая баланса. Ровный рост предпочтительнее резких взлетов и падений.

· Максимальная просадка (Max Drawdown): Максимальный пиковый убыток от предыдущего пика капитала. Это ваш главный стресс-тест. Если просадка 40%, а вы к ней психологически не готовы – система вам не подходит.

· Profit Factor (Прибыльность): (Сумма прибылей) / (Сумма убытков). Значение > 1.2 – минимально приемлемое, > 1.5 – хорошее.

· Количество сделок: Для статистической значимости нужно несколько сотен сделок (не 10-20).

2. Оптимизация – Тонкая настройка (ОПАСНАЯ ЗОНА).

· Что это? Подбор наилучших параметров (периоды индикаторов, уровни стоп-лосса) на исторических данных.

· ЛОВУШКА ПЕРЕОПТИМИЗАЦИИ (Кривая подгонка): Когда вы создаете идеальную систему для прошлого, которая бесполезна в будущем. Признаки: десятки параметров, чрезмерно высокая прибыль в бэктесте (>50% в месяц), резкие пики на кривой баланса.

· Как избежать?

· Принцип «Бритвы Оккама»: Чем проще система и меньше параметров, тем лучше.

· Тест на "незнакомых" данных: Оптимизируйте на периоде 2015-2020 гг., а проверьте на 2021-2023 гг.

· Walk-Forward Optimization (WFO): «Скользящая» оптимизация. Параметры подбираются на одном историческом окне, а тестируются на последующем, затем окно сдвигается вперед. Это золотой стандарт проверки устойчивости.

3. Форвард-тестирование (Forward Test / Paper Trading) – Репетиция в прямом эфире.

· Что это? Запуск робота на ДЕМО-СЧЕТЕ в режиме реального времени, но на виртуальные деньги. Он торгует по текущим, а не историческим, котировкам.

· Цель: Убедиться, что робот работает в реальных рыночных условиях с учетом спредов, проскальзываний, задержек исполнения. Проверить корректность кода и логики на "живом" потоке данных.

· Правило: Тестируйте не менее 2-3 месяцев и наберите не менее 100 сделок. Только после этого можно думать о реальных деньгах.

Этап 4: ЗАПУСК – Переход в боевой режим

Самый волнительный и ответственный момент.

1. Выделение капитала: Используйте только рисковый капитал, потеря которого не повлияет на вашу жизнь.

2. Начало с минимального объема: Запустите робота с лотом в 5-10 раз меньше расчетного. Например, если по вашим правилам лот для депозита $10,000 = 0.1, начните с 0.01. Цель – проверить исполнение и психологическую устойчивость.

3. Техническая инфраструктура: Обязательно используйте VPS (Виртуальный частный сервер) с хорошим аптаймом, расположенный рядом с серверами брокера. Это гарантирует, что робот не отключится из-за вашего сбоя интернета или выключенного компьютера.

Этап 5: МОНИТОРИНГ И УПРАВЛЕНИЕ – Не усыпляйте бдительность

Запуск робота – не финал, а начало нового этапа. Вы – пилот, а робот – автопилот. Пилот должен контролировать приборы.

· Что мониторить ежедневно (10-15 минут):

1. Исполнение ордеров: Не было ли критических проскальзываний, реквот (отказов брокера)?

2. Соответствие стратегии: Сделки открываются по правилам? Проверьте логи.

3. Состояние счета: Глубина текущей просадки. Не приближается ли к максимальной расчетной?

4. Рыночный контекст: Не начался ли период экстремальной волатильности (войны, решения ЦБ), для которого робот не предназначен?

· Когда ВМЕШАТЬСЯ (важнейший навык):

· Технический сбой (потеря связи, ошибка в логах).

· "Черный лебедь" – форс-мажорное рыночное событие.

· Достигнут лимит убытков: Например, просадка превысила 80% от расчетной Max Drawdown. Нужно остановить робота и разбираться.

· Декларативное изменение: Вы решили модернизировать стратегию.

· Постоянное улучшение: Анализируйте убыточные сделки. Можно ли добавить фильтр? Периодически проводите ре-оптимизацию на новых данных (но снова через все этапы тестирования!).

-–

Вывод главы:

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

Уважайте этот процесс. Дисциплинированное следование ему – это то, что отделяет мечтателя от системного алготрейдера. В следующей части мы перейдем к самому интересному – галерее конкретных идей для ваших будущих торговых роботов.

Часть 2: Галерея стратегий: 10 роботов для Форекса

Робот 1: «Следователь за трендом» (Trend Follower) – Python версия для Backtesting

Вот полная реализация стратегии Trend Follower на Python с использованием библиотеки backtrader для бэктестинга и анализа:

```python

# trend_follower_backtest.py

import backtrader as bt

import backtrader.analyzers as btanalyzers

import pandas as pd

import yfinance as yf

from datetime import datetime, timedelta

import matplotlib.pyplot as plt

# =====================================================================

# 1. СОЗДАНИЕ СТРАТЕГИИ

# =====================================================================

class TrendFollowerStrategy(bt.Strategy):

"""

Стратегия следования за трендом

Правила:

1. Покупка: когда быстрая MA (50) пересекает медленную (200) снизу вверх И ADX > 25

2. Закрытие: при обратном пересечении MA или по стоп-лоссу/тейк-профиту

"""

params = (

('fast_ma', 50), # Период быстрой скользящей средней

('slow_ma', 200), # Период медленной скользящей средней

('adx_period', 14), # Период ADX

('adx_threshold', 25),# Пороговое значение ADX для силы тренда

('stop_loss', 0.02), # Стоп-лосс 2%

('take_profit', 0.04),# Тейк-профит 4%

('risk_per_trade', 0.01), # Риск на сделку 1% от капитала

('use_atr_filter', True), # Использовать фильтр ATR

('atr_period', 14), # Период ATR

('atr_multiplier', 2),# Множитель ATR для стоп-лосса

('printlog', False), # Вывод логов

)

def __init__(self):

"""Инициализация индикаторов"""

# Создаем индикаторы

self.fast_ma = bt.indicators.SimpleMovingAverage(

self.data.close, period=self.params.fast_ma

)

self.slow_ma = bt.indicators.SimpleMovingAverage(

self.data.close, period=self.params.slow_ma

)

# ADX индикатор (направленность тренда)

self.adx = bt.indicators.AverageDirectionalMovementIndex(

self.data, period=self.params.adx_period

)

# ATR для фильтра волатильности и расчета стоп-лосса

self.atr = bt.indicators.AverageTrueRange(

self.data, period=self.params.atr_period

)

# Переменные для отслеживания состояния

self.order = None

self.buyprice = None

self.buycomm = None

# Для логирования

self.trades = []

self.current_trade = {}

def log(self, txt, dt=None, doprint=False):

"""Метод для логирования"""

if self.params.printlog or doprint:

dt = dt or self.datas[0].datetime.date(0)

print(f'{dt.isoformat()} {txt}')

def notify_order(self, order):

"""Обработка изменения статуса ордера"""

if order.status in [order.Submitted, order.Accepted]:

# Ордер отправлен/принят – ничего не делаем

return

if order.status in [order.Completed]:

if order.isbuy():

self.log(

f'ПОКУПКА ИСПОЛНЕНА, Цена: {order.executed.price:.2f}, '

f'Стоимость: {order.executed.value:.2f}, '

f'Комиссия: {order.executed.comm:.2f}'

)

self.buyprice = order.executed.price

self.buycomm = order.executed.comm

# Устанавливаем стоп-лосс и тейк-профит

if self.params.use_atr_filter:

sl = self.buyprice – self.atr[0] * self.params.atr_multiplier

tp = self.buyprice + self.atr[0] * self.params.atr_multiplier * 2

else:

sl = self.buyprice * (1 – self.params.stop_loss)

tp = self.buyprice * (1 + self.params.take_profit)

self.sell(exectype=bt.Order.StopTrail, price=sl)

self.sell(exectype=bt.Order.Limit, price=tp)

# Сохраняем информацию о сделке

self.current_trade = {

'entry_date': self.datas[0].datetime.date(0),

'entry_price': order.executed.price,

'stop_loss': sl,

'take_profit': tp,

'size': order.executed.size

}

elif order.issell():

self.log(

f'ПРОДАЖА ИСПОЛНЕНА, Цена: {order.executed.price:.2f}, '

f'Стоимость: {order.executed.value:.2f}, '

f'Комиссия: {order.executed.comm:.2f}'

)

# Фиксируем завершение сделки

if self.current_trade:

self.current_trade['exit_date'] = self.datas[0].datetime.date(0)

self.current_trade['exit_price'] = order.executed.price

self.current_trade['pnl'] = (

(order.executed.price – self.current_trade['entry_price']) *

self.current_trade['size']

)

self.current_trade['pnl_percent'] = (

(order.executed.price / self.current_trade['entry_price'] – 1) * 100

)

self.trades.append(self.current_trade.copy())

self.current_trade = {}

elif order.status in [order.Canceled, order.Margin, order.Rejected]:

self.log(f'Ордер отменен/отклонен: {order.getstatusname()}')

self.order = None

def notify_trade(self, trade):

"""Обработка изменения статуса сделки"""

if not trade.isclosed:

return

self.log(f'СДЕЛКА ЗАКРЫТА, Прибыль: {trade.pnl:.2f}, Чистая прибыль: {trade.pnlcomm:.2f}')

def next(self):

"""Основная логика на каждом новом баре"""

# Пропускаем если ордер уже открыт

if self.order:

return

# Проверяем, есть ли открытая позиция

if not self.position:

# УСЛОВИЕ ДЛЯ ПОКУПКИ:

# 1. Быстрая MA пересекает медленную снизу вверх

# 2. ADX > порогового значения (сила тренда)

crossover_up = (self.fast_ma[-1] < self.slow_ma[-1] and

self.fast_ma[0] > self.slow_ma[0])

strong_trend = self.adx[0] > self.params.adx_threshold

if crossover_up and strong_trend:

# Рассчитываем размер позиции на основе риска

capital = self.broker.getvalue()

risk_amount = capital * self.params.risk_per_trade

if self.params.use_atr_filter:

stop_distance = self.atr[0] * self.params.atr_multiplier

else:

stop_distance = self.data.close[0] * self.params.stop_loss

if stop_distance > 0:

size = risk_amount / stop_distance

size = min(size, capital * 0.1 / self.data.close[0]) # Не более 10% капитала

self.log(f'СИГНАЛ НА ПОКУПКУ: цена={self.data.close[0]:.2f}, '

f'ADX={self.adx[0]:.2f}, размер={size:.2f}')

self.order = self.buy(size=size)

else:

# УСЛОВИЕ ДЛЯ ЗАКРЫТИЯ ПОЗИЦИИ:

# Быстрая MA пересекает медленную сверху вниз

crossover_down = (self.fast_ma[-1] > self.slow_ma[-1] and

self.fast_ma[0] < self.slow_ma[0])

if crossover_down:

self.log(f'СИГНАЛ НА ЗАКРЫТИЕ: цена={self.data.close[0]:.2f}')

self.order = self.close()

# =====================================================================

# 2. КЛАСС ДЛЯ ОПТИМИЗАЦИИ ПАРАМЕТРОВ

# =====================================================================

class TrendFollowerOptimizer(bt.Strategy):

"""Версия стратегии для оптимизации параметров"""

params = (

('fast_ma', 50),

('slow_ma', 200),

('adx_threshold', 25),

('risk_per_trade', 0.01),

)

def __init__(self):

self.fast_ma = bt.indicators.SMA(self.data.close, period=self.p.fast_ma)

self.slow_ma = bt.indicators.SMA(self.data.close, period=self.p.slow_ma)

self.adx = bt.indicators.ADX(self.data, period=14)

self.order = None

def next(self):

if self.order:

return

if not self.position:

if (self.fast_ma[-1] < self.slow_ma[-1] and

self.fast_ma[0] > self.slow_ma[0] and

self.adx[0] > self.p.adx_threshold):

size = self.broker.getvalue() * self.p.risk_per_trade / self.data.close[0]

self.order = self.buy(size=size)

else:

if self.fast_ma[-1] > self.slow_ma[-1] and self.fast_ma[0] < self.slow_ma[0]:

self.order = self.close()

# =====================================================================

# 3. ФУНКЦИИ ДЛЯ ТЕСТИРОВАНИЯ И АНАЛИЗА

# =====================================================================

def download_data(symbol='EURUSD=X', start_date='2020-01-01', end_date='2023-12-31'):

"""Загрузка данных с Yahoo Finance"""

print(f"Загрузка данных для {symbol}…")

data = yf.download(symbol, start=start_date, end=end_date, progress=False)

# Преобразуем индексы для backtrader

data.index = pd.to_datetime(data.index)

data = data[['Open', 'High', 'Low', 'Close', 'Volume']]

return data

def run_backtest(data, initial_cash=10000, commission=0.001, **strategy_params):

"""Запуск бэктеста"""

cerebro = bt.Cerebro()

# Добавляем данные

data_feed = bt.feeds.PandasData(dataname=data)

cerebro.adddata(data_feed)

# Добавляем стратегию

cerebro.addstrategy(TrendFollowerStrategy, **strategy_params)

# Настройки брокера

cerebro.broker.setcash(initial_cash)

cerebro.broker.setcommission(commission=commission)

# Добавляем анализаторы

cerebro.addanalyzer(btanalyzers.Returns, _name='returns')

cerebro.addanalyzer(btanalyzers.SharpeRatio, _name='sharpe', riskfreerate=0.0)

cerebro.addanalyzer(btanalyzers.DrawDown, _name='drawdown')

cerebro.addanalyzer(btanalyzers.TradeAnalyzer, _name='trades')

cerebro.addanalyzer(btanalyzers.SQN, _name='sqn')

print(f'Начальный капитал: {initial_cash:.2f}')

print(f'Комиссия: {commission*100:.2f}%')

# Запуск

results = cerebro.run()

strat = results[0]

# Вывод результатов

print('\n' + '='*50)

print('РЕЗУЛЬТАТЫ БЭКТЕСТА')

print('='*50)

final_value = cerebro.broker.getvalue()

total_return = (final_value / initial_cash – 1) * 100

print(f'Конечный капитал: {final_value:.2f}')

print(f'Общая доходность: {total_return:.2f}%')

# Анализ результатов

if hasattr(strat, 'analyzers'):

returns = strat.analyzers.returns.get_analysis()

sharpe = strat.analyzers.sharpe.get_analysis()

drawdown = strat.analyzers.drawdown.get_analysis()

trades = strat.analyzers.trades.get_analysis()

sqn = strat.analyzers.sqn.get_analysis()

print(f'\nАНАЛИТИКА:')

print(f'Sharpe Ratio: {sharpe.get("sharperatio", 0):.3f}')

print(f'Максимальная просадка: {drawdown.max.drawdown:.2f}%')

print(f'Продолжительность просадки: {drawdown.max.len} дней')

if trades.total.total:

print(f'\nСТАТИСТИКА СДЕЛОК:')

print(f'Всего сделок: {trades.total.total}')

print(f'Прибыльных: {trades.won.total} ({trades.won.total/trades.total.total*100:.1f}%)')

print(f'Убыточных: {trades.lost.total} ({trades.lost.total/trades.total.total*100:.1f}%)')

print(f'Profit Factor: {trades.won.pnl.total/abs(trades.lost.pnl.total):.2f}')

print(f'Средняя прибыль: {trades.won.pnl.average:.2f}')

print(f'Средний убыток: {trades.lost.pnl.average:.2f}')

print(f'SQN: {sqn.sqn:.2f}')

# Возвращаем детали сделок для дальнейшего анализа

trades_details = getattr(strat, 'trades', [])

return cerebro, strat, trades_details

def optimize_parameters(data, parameter_ranges):

"""Оптимизация параметров стратегии"""

cerebro = bt.Cerebro(optreturn=False)

# Добавляем данные

data_feed = bt.feeds.PandasData(dataname=data)

cerebro.adddata(data_feed)

# Добавляем стратегию с параметрами для оптимизации

cerebro.optstrategy(

TrendFollowerOptimizer,

fast_ma=parameter_ranges.get('fast_ma', range(10, 101, 10)),

slow_ma=parameter_ranges.get('slow_ma', range(50, 301, 50)),

adx_threshold=parameter_ranges.get('adx_threshold', range(20, 41, 5)),

risk_per_trade=parameter_ranges.get('risk_per_trade', [0.005, 0.01, 0.02])

)

# Настройки

cerebro.broker.setcash(10000)

cerebro.broker.setcommission(commission=0.001)

# Оптимизация

print("Запуск оптимизации параметров…")

opt_results = cerebro.run(maxcpus=1)

# Анализ результатов оптимизации

results = []

for run in opt_results:

for strat in run:

# Собираем статистику для каждого набора параметров

value = cerebro.broker.getvalue()

returns = (value / 10000 – 1) * 100

results.append({

'fast_ma': strat.params.fast_ma,

'slow_ma': strat.params.slow_ma,

'adx_threshold': strat.params.adx_threshold,

'risk_per_trade': strat.params.risk_per_trade,

'final_value': value,

'returns': returns

})

# Создаем DataFrame с результатами

results_df = pd.DataFrame(results)

results_df = results_df.sort_values('final_value', ascending=False)

return results_df

def plot_results(cerebro, save_path='trend_follower_results.png'):

"""Визуализация результатов"""

# График 1: Кривая баланса

fig = cerebro.plot(style='candlestick', iplot=False)[0][0]

fig.set_size_inches(14, 8)

fig.suptitle('Trend Follower Strategy – Equity Curve', fontsize=16)

# Сохраняем график

plt.tight_layout()

plt.savefig(save_path, dpi=100, bbox_inches='tight')

plt.show()

return fig

def generate_report(strategy_params, trades_details, filename='trend_follower_report.txt'):

"""Генерация детального отчета"""

with open(filename, 'w', encoding='utf-8') as f:

f.write("="*60 + "\n")

f.write("ОТЧЕТ ПО СТРАТЕГИИ TREND FOLLOWER\n")

f.write("="*60 + "\n\n")

f.write("ПАРАМЕТРЫ СТРАТЕГИИ:\n")

f.write("-"*40 + "\n")

for key, value in strategy_params.items():

f.write(f"{key}: {value}\n")

f.write("\n" + "="*60 + "\n\n")

if trades_details:

f.write("ДЕТАЛИ СДЕЛОК:\n")

f.write("-"*40 + "\n")

total_pnl = 0

winning_trades = 0

for i, trade in enumerate(trades_details, 1):

pnl = trade.get('pnl', 0)

pnl_percent = trade.get('pnl_percent', 0)

f.write(f"\nСделка #{i}:\n")

f.write(f" Дата входа: {trade.get('entry_date')}\n")

f.write(f" Цена входа: {trade.get('entry_price', 0):.4f}\n")

f.write(f" Дата выхода: {trade.get('exit_date')}\n")

f.write(f" Цена выхода: {trade.get('exit_price', 0):.4f}\n")

f.write(f" P&L: {pnl:.2f} ({pnl_percent:.2f}%)\n")

total_pnl += pnl

if pnl > 0:

winning_trades += 1

f.write("\n" + "="*60 + "\n")

f.write(f"ИТОГИ:\n")

f.write(f"Всего сделок: {len(trades_details)}\n")

f.write(f"Прибыльных сделок: {winning_trades} ({winning_trades/len(trades_details)*100:.1f}%)\n")

f.write(f"Общий P&L: {total_pnl:.2f}\n")

print(f"Отчет сохранен в файл: {filename}")

# =====================================================================

# 4. ОСНОВНОЙ СКРИПТ ДЛЯ ЗАПУСКА

# =====================================================================

def main():

"""Основная функция для запуска бэктеста"""

print("="*60)

print("TREND FOLLOWER STRATEGY BACKTEST")

print("="*60)

# 1. Загружаем данные

symbol = 'EURUSD=X' # EUR/USD

data = download_data(

symbol=symbol,

start_date='2020-01-01',

end_date='2023-12-31'

)

if data.empty:

print("Ошибка загрузки данных!")

Конец ознакомительного фрагмента.

Текст предоставлен ООО «Литрес».

Прочитайте эту книгу целиком, купив полную легальную версию на Литрес.

Безопасно оплатить книгу можно банковской картой Visa, MasterCard, Maestro, со счета мобильного телефона, с платежного терминала, в салоне МТС или Связной, через PayPal, WebMoney, Яндекс.Деньги, QIWI Кошелек, бонусными картами или другим удобным Вам способом.