
Создание самооптимизирующихся советников на MQL5 (Часть 2): Стратегия скальпинга на USDJPY
В предыдущей статье серии мы построили модель линейной регрессии для создания сигналов на вход и выход для нашего торгового приложения. Оглядываясь назад, можно сказать, что нам, возможно, не нужны все элементы, имеющиеся в модели машинного обучения. Вместо этого мы можем рассматривать модели машинного обучения как пример того, как решать реальные проблемы с использованием динамических правил. Затем мы можем использовать те же простые принципы мышления и логики, чтобы потенциально вывести наши торговые приложения на более высокий уровень прибыльности без необходимости создания гигантской базы кодов для обслуживания.
Здесь я намерен торговать парой USDJPY на дневном таймфрейме. Наша торговая стратегия будет основана на свечных моделях. В частности, мы будем торговать разворотные модели, созданные поглощающими свечами. Наши правила для бычьей поглощающей свечи будут соблюдены, если наша цена открытия ниже цены закрытия предыдущего дня, а цена закрытия выше цены открытия предыдущего дня. Пример показан на рис. 1 ниже. Считается, что эти свечные модели показывают, что определенный уровень цен был отвергнут со значительной силой.
Рис. 1. Мы обнаружили пример нашей бычьей свечной модели
Трейдеры считают, что модели поглощающих свечей являются признаком того, что на рынке формируется новый тренд. Если они идентифицированы правильно, за ними обычно следует последовательное движение цены в направлении нового тренда (см. рис. 2 ниже). Это создает основу торговой стратегии и правильного определения торгового паттерна. Медвежьи свечи поглощения можно использовать для определения начала нисходящих трендов. Мы используем те же правила, которые только что описали, но в противоположном ключе.
Рис. 2. В этом конкретном примере наша свечная модель оказалась надежной
Обычно считается, что эти стратегии справедливы для всех таймфреймов. Однако я считаю, что дневной временной интервал может быть наиболее надежным. Я выбрал его в качестве предпочтительного таймфрейма для этого упражнения. Попробуем реализовать стратегию торговли сигналами на вход, полученными на основе нашего понимания этих конкретных рыночных паттернов. Также проверим, сможем ли мы увеличить нашу прибыльность, внеся изменения в первоначальную стратегию.
Начало работы с MQL5
Наша программа будет состоять из 6 основных частей, которые нам понадобятся для достижения нашей цели — прибыльной торговли по свечным паттернам.
Часть | Назначение |
---|---|
Инициализация | Эта часть нашей системы будет отвечать за загрузку и установку глобальных переменных. |
Деинициализация | Освободите ресурсы, которые наше приложение больше не использует, чтобы обеспечить стабильную работу конечного пользователя. |
OnTick | Обновление системных переменных и сканирование текущего графика на предмет наличия у нас свечных паттернов. |
Пользовательские функции | Специализированные работы, необходимые для достижения нашей цели. |
Системные константы | Константы, которые не предназначены для изменения конечным пользователем. |
Глобальные переменные | Отслеживание последнего типа размещенного нами ордера, текущих предлагаемых рыночных цен и уровней волатильности. Для этого были созданы такие переменные, как trade и bid. ATR поможет разместить стоп-лоссы и фиксировать прибыль по нашим позициям. |
Первоначально наша стратегия будет заключать сделки только после того, как будет найден наш свечной паттерн. Если паттерн определен, а у нас нет открытых позиций, мы воспользуемся сигналом и применим ATR, чтобы установить и скорректировать наш стоп-лосс. В противном случае наша система будет управлять всеми открытыми нами сделками. Следовательно, глобальные переменные нашей системы будут:
Переменная | Описание |
---|---|
trade | Предоставляет информацию о типе позиции, которая у нас открыта в настоящее время, что облегчит нам обновление наших стоп-ордеров и решение любых других задач, которые могут возникнуть в будущем. |
atr_handler | Важно для последовательного обновления наших стоп-лоссов. |
bid, ask | Отслеживание рыночных цен. |
Для начала мы создадим тестовую версию нашей торговой стратегии. Начнем с определения системных констант. Эти константы будут созданы с помощью директивы #define. Директива #define указывает препроцессору, встроенному в наш редактор MQL5, заменить любое вхождение указанного нами идентификатора макроса и поместить на его место то, что мы назначили справа от идентификатора макроса.
Первая системная константа, которую мы определили, — SYMBOL. При компиляции нашего приложения препроцессор заменит все вхождения SYMBOL в нашем коде на значение USDJPY. Эта простая функция дает нам полный контроль над системой и гарантирует единообразие во всех наших тестах.
//+------------------------------------------------------------------+ //| Dynamic Stops Benchmark.mq5 | //| Gamuchirai Zororo Ndawana | //| https://www.mql5.com/en/gamuchiraindawa | //+------------------------------------------------------------------+ #property copyright "Gamuchirai Zororo Ndawana" #property link "https://www.mql5.com/en/gamuchiraindawa" #property version "1.00" //+------------------------------------------------------------------+ //| This trading application is intended to serve as our benchmark. | //| Our goal is to learn what it will take to surpass the benchmark. | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| System constants | //+------------------------------------------------------------------+ #define SYMBOL "USDJPY" //--- System pair #define DAILY PERIOD_D1 //--- Daily time frame #define VOL 0.1 //--- Trading volume #define ATR_PERIOD 14 //--- Technical Indicator ATR Period #define ATR_MULTIPLE 2 //--- Stop loss ATR multiple
Нам также потребуется загрузить торговую библиотеку.
//+------------------------------------------------------------------+ //| Libraries | //+------------------------------------------------------------------+ #include <Trade/Trade.mqh> CTrade Trade;
Теперь определим наши глобальные переменные. Эти переменные помогут нам отслеживать нашу открытую позицию и текущие рыночные котировки.
//+------------------------------------------------------------------+ //| Global variables | //+------------------------------------------------------------------+ int trade = 0; int atr_handler; double atr[]; double bid,ask;
При инициализации мы вызовем специализированную функцию, отвечающую за инициализацию наших системных переменных.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- setup(); //--- return(INIT_SUCCEEDED); }
Если мы больше не будем использовать наше торговое приложение, то мы опубликуем технические индикаторы, которые мы больше не используем.
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Release the indicator release(); }
Будем обновлять наши системные переменные один раз в конце дня. Эту настройку можно изменить для лучшего управления рисками. Я решил обновлять системные переменные только один раз в день, чтобы тестирование на истории завершалось своевременно и нам было легче сравнивать вносимые нами изменения.
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- update(); } //+------------------------------------------------------------------+
Первая настраиваемая функция, которую мы создадим, будет отвечать за высвобождение системных ресурсов, которые мы больше не потребляем.
//+------------------------------------------------------------------+ //| Custom Functions | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Release variables we don't need | //+------------------------------------------------------------------+ void release(void) { IndicatorRelease(atr_handler); }
Будем обновлять наши системные переменные раз в день.
//+------------------------------------------------------------------+ //| Update system | //+------------------------------------------------------------------+ void update(void) { static datetime daily_timestamp; datetime daily_time = iTime(SYMBOL,DAILY,0); if(daily_timestamp != daily_time) { //--- Update the time daily_timestamp = daily_time; //--- Update system variables daily_update(); //--- Do we have an oppurtunity to trade? if((PositionsTotal() == 0)) find_setup(); //--- Do we have positions to manage? if(PositionsTotal() > 0) manage_setup(); } }
Управляйте своими сделками, обновляя стоп-лосс и тейк-профит только в том случае, если новое положение стоп-лосса или тейк-профита окажется более прибыльным.
//+------------------------------------------------------------------+ //| Manage our trades | //+------------------------------------------------------------------+ void manage_setup(void) { //--- Select the position if(PositionSelect(SYMBOL)) { //--- Get ready to update the SL/TP double initial_sl = PositionGetDouble(POSITION_SL); double initial_tp = PositionGetDouble(POSITION_TP); double buy_sl = (ask - (ATR_MULTIPLE * atr[0])); double sell_sl = (bid + (ATR_MULTIPLE * atr[0])); double buy_tp = (ask + (ATR_MULTIPLE * atr[0])); double sell_tp = (bid - (ATR_MULTIPLE * atr[0])); double new_sl = ((trade == 1) && (initial_sl < buy_sl))? (buy_sl) : ((trade == -1) && (initial_sl > sell_sl)) ? (sell_sl) : (initial_sl); double new_tp = ((trade == 1) && (initial_tp < buy_tp))? (buy_tp) : ((trade == -1) && (initial_tp > sell_tp)) ? (sell_tp) : (initial_tp); //--- Update the position Trade.PositionModify(SYMBOL,new_sl,new_tp); } }
Настроим технические индикаторы. На данный момент нам необходимо управлять только одним техническим индикатором.
//+------------------------------------------------------------------+ //| Get our technical indicators ready | //+------------------------------------------------------------------+ void setup(void) { atr_handler = iATR(SYMBOL,DAILY,ATR_PERIOD); }
Обновим состояние системы.
//+------------------------------------------------------------------+ //| Daily update routine | //+------------------------------------------------------------------+ void daily_update(void) { //--- Get current prices ask = SymbolInfoDouble(SYMBOL,SYMBOL_ASK); bid = SymbolInfoDouble(SYMBOL,SYMBOL_BID); //--- Update Technical Indicators CopyBuffer(atr_handler,0,0,1,atr); //--- Check for engulfing candles. int candles_state = check_candles(); //--- Give feedback Comment("Candle State: ",candles_state); }
Проверим наш свечной паттерн. Если паттерн найден, вернем 1 или -1 и разместим длинную или короткую сделку. В противном случае подождем.
//+------------------------------------------------------------------+ //| Check if we have any engulfing candles | //+------------------------------------------------------------------+ int check_candles(void) { //--- Return 1 if we have a bullish engulfing candle if((iOpen(SYMBOL,DAILY,0) < iClose(SYMBOL,DAILY,1)) && (iClose(SYMBOL,DAILY,0) > iOpen(SYMBOL,DAILY,1))) return(1); //--- Return -1 if we have a bearish engulfing candle if((iOpen(SYMBOL,DAILY,0) > iClose(SYMBOL,DAILY,1)) && (iClose(SYMBOL,DAILY,0) < iOpen(SYMBOL,DAILY,1))) return(-1); //--- Otherwise return 0 return(0); }
Наша система поймет, что нашла торговую установку, если состояние свечи не равно 0. В противном случае на данный момент больше ничего делать не нужно.
//+------------------------------------------------------------------+ //| Find setup | //+------------------------------------------------------------------+ void find_setup(void) { //--- Our sentiment is bullish int candles_state = check_candles(); if(candles_state == 1) { Trade.Buy(VOL,SYMBOL,ask,(ask - (ATR_MULTIPLE * atr[0])),(ask + (ATR_MULTIPLE * atr[0])),""); trade = 1; } //--- Our sentiment is bearish if(candles_state == -1) { Trade.Sell(VOL,SYMBOL,bid,(bid + (ATR_MULTIPLE * atr[0])),(bid - (ATR_MULTIPLE * atr[0])),""); trade = -1; } } //+------------------------------------------------------------------+
На рис. 3 ниже мы можем увидеть, как выглядит наша система. Наша система отслеживает наличие или отсутствие свечного паттерна и размещает сделки, если паттерн обнаружен. В рамках нашей текущих настроек позиции стоп-лосса и тейк-профита будут перемещаться один раз в день, в конце дня.
Рис. 3. Визуализация нашей торговой стратегии на дневном таймфрейме USDJPY
Протестируем нашу новую стратегию на исторических данных за 4 года: с 1 января 2020 года по конец ноября 2024 года. Если вы хотите следовать инструкциям и внести какие-либо изменения в эти настройки, не забудьте также внести соответствующие изменения в системные переменные. В противном случае наша система продолжит торговать парой USDJPY на дневном таймфрейме независимо от того, какие символы и таймфрейм мы укажем.
Рис. 4. Основные настройки для нашего тестирования на истории
Случайная задержка наиболее близка к реальным торговым сценариям и позволяет нам провести стресс-тест нашей системы. Обязательно скорректируйте Deposit и кредитное плечо счета в соответствии с предполагаемой торговой настройкой, если вы планируете использовать стратегию на практике.
Рис. 5: Выбор типа моделирования и размера счета для тестирования на истории
Кривая эквити, полученная в результате реализации данной стратегии, является многообещающей. В ходе тестирования на истории наша стратегия скальпинга увеличила размер счета примерно на 4%. Как и любая торговая стратегия, она пережила длительные периоды убытков. Но что весьма примечательно в этой стратегии, так это ее способность восстанавливаться после периодов потерь.
Рис. 6. Визуализация баланса нашего торгового счета с течением времени
Давайте теперь подробнее рассмотрим эффективность нашей стратегии. В нынешнем виде наша стратегия имела коэффициент Шарпа 1,12 и показатель успешности 44,68%. Что необходимо сделать, чтобы сократить размер среднего убытка с USD 133,22 и приблизить его к 0, минимизировав при этом наше влияние на среднюю прибыль?
Рис. 7: Подробный анализ результатов нашего тестирования на истории
Улучшение наших результатов
В нынешнем состоянии наша система прибыльна. Можно ли внести какие-либо изменения, которые позволят нам лучше контролировать убыточные сделки? Я предложу несколько изменений в первоначальную стратегию:
Предлагаемое изменение | Предполагаемая цель |
---|---|
Дополнительное подтверждение | Используя дополнительную стратегию подтверждения наряду с нашей уже прибыльной стратегией, мы потенциально можем отсортировать больше убыточных сделок. |
Дополнительную отступ к стоп-лоссу | Мы хотим свести к минимуму количество случаев выхода из прибыльных сделок. |
Учет волатильности рынка | Каждый рынок потенциально имеет уникальные уровни волатильности. Наша торговая стратегия должна попытаться учесть исторические уровни волатильности, проанализировать текущие уровни цен с определенным уровнем контекста, подобно профессиональным трейдерам. |
Надеемся, что благодаря внедрению этих изменений нам удастся сократить долю убыточных сделок. При принятии таких решений всегда приходится идти на компромисс. В конечном счете, наша новая стратегия время от времени будет упускать прибыльные сделки, которые наша старая стратегия легко бы заметила.
В конечном итоге отсутствие контроля над размером наших средних убытков может стоить нам всей прибыли, которую мы накопили. Чтобы реализовать желаемые изменения, нам придется внести изменения в текущую версию приложения.
Изменение системы | Описание |
---|---|
Новые системные переменные | Чтобы учесть волатильность рынка, нам сначала нужно решить, какой объем данных из прошлого нам следует извлечь. За нас этим займется новая системная переменная fetch. Кроме того, нам потребуется зафиксировать параметры всех технических индикаторов, которые мы будем использовать. |
Технические индикаторы | Дополнительное подтверждение мы можем получить, используя торговые стратегии на основе технических индикаторов. Сегодня мы будем использовать стратегию канала скользящей средней. Поэтому мы создадим новые обработчики индикаторов и буферы для хранения этой новой информации. |
Слияние сигналов | Создадим новую глобальную переменную sentiment. Ее значение будет равно 1 или -1, когда и наша свечная модель, и технические индикаторы либо оба бычьи (1), либо оба медвежьи (-1). В противном случае она будет равна 0. Наша система будет размещать сделки только в том случае, если значение sentiment не равно 0. |
Настраиваемые функции | Чтобы добиться желаемого поведения нашей системы, нам придется расширить некоторые из уже созданных нами специализированных функций, а также создать несколько новых функций. |
Обзор стратегии подтверждения
Наша стратегия подтверждения будет основана на торговых стратегиях канала скользящей средней. Эта стратегия создается с помощью двух скользящих средних, следующих за максимальной и минимальной ценой соответственно. Две скользящие средние образуют канал. Обратите внимание, скользящие средние не пересекаются друг с другом. Таким образом, наши сигналы на вход генерируются, когда свеча полностью формируется за пределами области между двумя скользящими средними.
Обоснование этой стратегии заключается в том, что уровни цен между максимальной и минимальной скользящей средней считаются стабильными. При этом когда уровни цен формируются за пределами области между двумя скользящими средними, мы ощущаем дисбаланс на рынке. Стратегия предполагает, что это формирование нового тренда в направлении дисбаланса. На рис. 8 ниже показано, как мы будем использовать эту стратегию.
Красная стрелка обозначает оптимальную область для открытия короткой позиции согласно стратегии. Эта схема обычно считается действительной, пока цены не вернутся в пределы канала. В этот момент наши позиции могут быть закрыты, и мы будем ждать обнаружения следующего дисбаланса. Этот второй дисбаланс отмечен синей стрелкой. Поскольку дисбаланс появился выше нашего канала скользящей средней, мы интерпретируем это как сигнал к длинной позиции.
Рис. 8. Наша стратегия канала скользящей средней для определения точек входа и выхода
Мы расширим эту идею, также приняв во внимание исторические максимумы и минимумы, наблюдавшиеся на рынке. Рассчитаем срединное значение, образованное историческими максимумами и минимумами цен, предложенных на рынке за последний год. Кроме того, мы будем использовать эту информацию для ограничения или применения только размещения длинных позиций, когда цена закрытия находится выше исторической средней точки максимума-минимума, а для наших коротких позиций будет верно обратное.
Красная горизонтальная линия на рис. 9 символизирует среднее значение максимальных и минимальных цен за последний год. Эта срединная точка обновляется нашей системой каждый день и будет служить своеобразным увеличительным стеклом для нашего приложения, позволяя ему просматривать уровни цен.
Рис. 9. Историческая середина прошлого года по настоящее время между высокими и низкими ценами, предлагаемыми на рынке
Тип позиции | Критерии новой позиции |
---|---|
Покупка | Поглощающая бычья свеча сформировалась выше канала скользящей средней, а уровни цен поднялись выше уровней среднегодовой волатильности. |
Продажа | Поглощающая медвежья свеча сформировалась выше канала скользящей средней, а уровни цен поднялись выше уровней среднегодовой волатильности. |
Надеемся, что, используя наши две стратегии вместе, мы сможем отсортировать убыточные сделки, которые мешали нашей старой системе, и в то же время сохранить прибыльные сделки. Давайте приступим к внедрению этих изменений и посмотрим, насколько они будут эффективны. Сначала нам необходимо определить новые системные переменные, которые зафиксируют периоды нашего канала скользящей средней и объем исторических данных, которые мы будем извлекать для расчета нашей средней точки.
//+------------------------------------------------------------------+ //| USDJPY Price Action Benchmark 2 | //| Gamuchirai Zororo Ndawana | //| https://www.mql5.com/en/gamuchiraindawa | //+------------------------------------------------------------------+ #property copyright "Gamuchirai Zororo Ndawana" #property link "https://www.mql5.com/en/gamuchiraindawa" #property version "1.00" //+------------------------------------------------------------------+ //| This trading application is intended to surpass our benchmark. | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| System constants | //+------------------------------------------------------------------+ //--- I have intentionally omitted parts of the system that remained unchanged #define FETCH 365 //--- How much should we fetch? #define MA_PERIOD 90 //--- Moving average period
Нам также понадобятся несколько дополнительных глобальных переменных для отслеживания определенных нами состояний рынка.
//+------------------------------------------------------------------+ //| Global variables | //+------------------------------------------------------------------+ int sentiment = 0; int trade = 0; int ma_high_handler, ma_low_handler; double ma_high[],ma_low[];
Тело нашего приложения останется прежним. Однако некоторые вызываемые функции изменились.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Setup our system varaibles setup(); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Release any resources release(); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- Update system variables update(); } //+------------------------------------------------------------------+
Давайте теперь рассмотрим изменения, внесенные в пользовательские функции. Первые два изменения будут заключаться в загрузке наших технических индикаторов и их последующей публикации.
//+------------------------------------------------------------------+ //| Custom Functions | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Release our technical indicators | //+------------------------------------------------------------------+ void release(void) { IndicatorRelease(atr_handler); IndicatorRelease(ma_low_handler); IndicatorRelease(ma_high_handler); }
Эти изменения в нашей кодовой базе идут рука об руку и просты для понимания.
//+------------------------------------------------------------------+ //| Get our technical indicators ready | //+------------------------------------------------------------------+ void setup(void) { atr_handler = iATR(SYMBOL,DAILY,ATR_PERIOD); ma_high_handler = iMA(SYMBOL,DAILY,MA_PERIOD,0,MODE_EMA,PRICE_HIGH); ma_low_handler = iMA(SYMBOL,DAILY,MA_PERIOD,0,MODE_EMA,PRICE_LOW); }
Нашу ежедневную процедуру обновлений также необходимо расширить. Теперь нам также интересно узнать, как текущий уровень цен соотносится с историческими уровнями шума, ожидаемыми от этого рынка. Если наши свечные модели и уровни цен дают нам соответствующие настроения, то мы будем искать подтверждение в нашем канале скользящей средней, если сейчас подходящее время для совершения сделки.
//+------------------------------------------------------------------+ //| Daily update routine | //+------------------------------------------------------------------+ void daily_update(void) { //--- Get current prices ask = SymbolInfoDouble(SYMBOL,SYMBOL_ASK); bid = SymbolInfoDouble(SYMBOL,SYMBOL_BID); //--- Update Technical Indicators CopyBuffer(atr_handler,0,0,1,atr); CopyBuffer(ma_high_handler,0,0,1,ma_high); CopyBuffer(ma_low_handler,0,0,1,ma_low); //--- Check for engulfing candles. int candles_state = check_candles(); //--- Compare current price levels to historical price levels in the market int price_state = check_price_levels(); //--- Check our tech //--- What is our sentiment? //--- Our sentiment is well defined. if(candles_state == price_state) sentiment = candles_state; //--- Wait. if(candles_state != price_state) sentiment = 0; //--- Give feedback Comment("Sentiment: ",sentiment,"\nCandle State: ",candles_state,"\nPrice State: ",price_state); }
Мы будем использовать векторный тип MQL5 для удобного расчета и отслеживания нашей рыночной статистики "на лету".
//+------------------------------------------------------------------+ //| Check if we are closer to the all time high or low | //+------------------------------------------------------------------+ int check_price_levels(void) { //--- Get historical prices vector highs = vector::Zeros(FETCH); vector lows = vector::Zeros(FETCH); highs.CopyRates(SYMBOL,DAILY,COPY_RATES_HIGH,0,FETCH); lows.CopyRates(SYMBOL,DAILY,COPY_RATES_LOW,0,FETCH); //--- First we shall calculate the mid point between the all time high and low vector mid = ((highs + lows) / 2); //--- Return 1 if we are above the mid point if(iClose(SYMBOL,DAILY,0) > mid.Mean()) return(1); //--- Return -1 if we are above the mid point if(iClose(SYMBOL,DAILY,0) < mid.Mean()) return(-1); //--- Otherwise return 0 return(0); }Наши новые правила поиска торговой установки будут учитывать два дополнительных фильтра. Уровень цен относительно годовой средней точки и уровень цен относительно канала скользящей средней. Если обе стратегии гармонируют, мы разместим нашу сделку соответствующим образом.
//+------------------------------------------------------------------+ //| Find setup | //+------------------------------------------------------------------+ void find_setup(void) { //--- Our sentiment is bullish if(sentiment == 1) { if((iOpen(SYMBOL,DAILY,0) > ma_high[0]) && (iClose(SYMBOL,DAILY,0) > ma_high[0])) { Trade.Buy(VOL,SYMBOL,ask,(ask - (ATR_MULTIPLE * atr[0])),(ask + (ATR_MULTIPLE * atr[0])),""); trade = 1; } } //--- Our sentiment is bearish if(sentiment == -1) { if((iOpen(SYMBOL,DAILY,0) < ma_low[0]) && (iClose(SYMBOL,DAILY,0) < ma_low[0])) { Trade.Sell(VOL,SYMBOL,bid,(bid + (ATR_MULTIPLE * atr[0])),(bid - (ATR_MULTIPLE * atr[0])),""); trade = -1; } } } //+------------------------------------------------------------------+
Давайте посмотрим на нашу стратегию в действии. Обратите внимание, что теперь наша стратегия отслеживает три условия, которые должны быть выполнены, прежде чем мы возьмем на себя обязательства по какой-либо позиции. Мы надеемся, что благодаря тщательному выбору правильных условий все они не будут удовлетворены случайно.
Рис. 10. Тестирование нашей пересмотренной стратегии скальпинга USDJPY на исторических рыночных данных
Как мы уже говорили ранее, настройки, касающиеся продолжительности и периода тестирования на истории, будут оставаться фиксированными для обеспечения единообразия в обоих наших тестах. Поэтому наши даты соответствуют датам предыдущего теста.
Рис. 11. Наши настройки для тестирования на истории будут фиксированными в обоих тестах
Не забывайте свободно настраивать эти параметры в соответствии с той средой, в которой вы планируете их использовать.
Рис. 12. Вторая группа настроек для нашего тестирования на истории
Кривая эквити, полученная с помощью нашей новой стратегии, имеет меньше периодов просадки по сравнению с нашим первым тестированием на истории. Например, в период с января 2020 года и до приближающегося декабря 2023 года кривая эквити, полученная в результате нашей первоначальной стратегии, находилась на одном месте, колеблясь вокруг первоначального баланса. В то время как наша новая кривая эквити не имеет этой нежелательной характеристики. Наша кривая эквити росла во время менее волатильного тренда с сентября 2022 года до конца тестирования на истории.
Рис. 13. Кривая эквити, полученная в результате нашей пересмотренной торговой стратегии
При дальнейшем рассмотрении мы видим, что нам удалось достичь нашей цели — приблизить средний убыток и долю убыточных сделок к 0. Однако нам удалось лишь незначительно сократить долю убыточных сделок — с 55% до 54%. Более того, наши изменения также снизили прибыльность нашей торговой стратегии. Это несущественная проблема, поскольку мы можем ее устранить, безопасно увеличив размер лота. Рынки — это динамичная среда, и введенные нами новые меры безопасности могут оказаться бесценными в будущем.
Рис. 14. Подробный анализ нашей второй торговой стратегии
Заключение
В этой статье мы рассмотрели потенциал торговли на основе сигналов, генерируемых свечными паттернами. Такие стратегии часто подвергаются критике, включая тот факт, что можно наблюдать формирование свечного паттерна, но за ним не всегда следует такое же ценовое движение.
Однако, я полагаю, что, внеся изменения, которые мы обсудили в этой стратегии, и добавив собственное понимание рынка, можно доказать прибыльность стратегии. Проблема в том, что нам не всегда очевидно, как вносимые нами изменения повлияют на прибыльность стратегии.
Файл | Описание |
---|---|
USDJPY Price Action Benchmark | Первоначальная, более волатильная версия нашей торговой стратегии. Более прибыльная, но и более рискованная. |
USDJPY Price Action Strategy 2 | Усовершенствованная версия стратегии. Столь же прибыльна и стремится минимизировать свои потери. |
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/16643





- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Могу ли я протестировать советник? Я скачал его, но по какой-то причине он не отображается в разделе "Советник". Любая помощь будет очень признательна. Спасибо.