English 中文 Español Deutsch 日本語 Português
preview
Разработка и тестирование торговых систем Aroon

Разработка и тестирование торговых систем Aroon

MetaTrader 5Трейдинг | 17 мая 2024, 14:27
1 156 0
Mohamed Abdelmaaboud
Mohamed Abdelmaaboud

Введение

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

Статьи такого типа полезны тем, что их изучение не занимает много времени, при этом большую часть работы вам необходимо проделать самостоятельно, чтобы найти оптимальные настройки торговой системы. Мы просто пытаемся представить здесь торговые инструменты, которые можно использовать индивидуально или в сочетании с другими инструментами, чтобы сэкономить вам время. Здесь также описано, как запрограммировать эти системы для тестирования в Тестере стратегий. Это означает, что вы можете сэкономить много времени, автоматизируя процесс тестирования вместо того, чтобы тестировать вручную.

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

В этой статье мы рассмотрим следующие темы:

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

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

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


Определение индикатора Aroon

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

Aroon был создан Тушаром С. Чанде в 1995 году. Основные цели индикатора – обнаруживать изменение тренда, а также измерять силу тренда. Индикатор может сделать это, измеряя, сколько времени прошло между максимумами и сколько времени прошло между минимумами за определенный период времени. Сильный восходящий тренд выражается в регулярном достижении новых максимумов, а сильный нисходящий тренд - в регулярном достижении новых минимумов. Индикатор обнаруживает эти закономерности и сигнализирует о них.

Индикатор Aroon состоит из двух линий: Aroon Up, которая измеряет силу восходящего тренда, и Aroon Down, которая измеряет силу нисходящего тренда. В этом контексте мы можем сказать, что когда Aroon Up находится выше Aroon Down, это указывает на бычий сигнал. Когда Aroon Down находится выше Aroon Up, это медвежий сигнал. Индикаторы Aroon также перемещаются или колеблются между уровнями от нуля до 100.

Ниже описано, как можно рассчитать технический индикатор Aroon:

Aroon Up     = 100 * ((n-H)/n)

Aroon Down = 100 * ((n-L)/n)

где:

  • Aroon Up - выражается в процентах от общего числа n-периодов и представляет собой количество периодов с момента последнего максимума n-периода.
  • Aroon Down - выражается в процентах от общего числа n-периодов и представляет собой количество периодов с момента последнего минимума n-периода.
  • H - количество периодов в течение заданного времени n-периодов с момента последнего максимума n-периода.
  • L - количество периодов в течение заданного времени n-периодов с момента последнего минимума n-периода.
  • n - период.


Стратегии Aroon

Рассмотрим две простые стратегии использования индикатора Aroon. Эти стратегии будут реализованы с помощью MQL5 для тестирования с помощью тестера стратегий, просмотра результатов каждой из них и сравнения.

Мы будем использовать две основные стратегии:

  • Aroon Crossover Strategy (стратегия пересечения)
  • Aroon Levels Strategy (стратегия уровней)

Aroon Crossover Strategy:

Нам нужно разместить ордер при пересечении верхней и нижней линий индикатора Aroon. Итак, нам нужно открыть ордер на покупку, когда мы видим, что Aroon Up (Upline) пересекает линию Aroon Down (Downline) вверх, и ордер на продажу, если Aroon Down пересекает вверх линию Aroon Up.

Upline > Downline ==> покупка

Downline > Upline ==> продажа

Aroon Levels Strategy:

Открываем ордер, если линия Aroon Down пересекает уровни 10 и 50 индикатора Aroon. Итак, нам нужно разместить ордер на покупку, если линия Aroon Down находится ниже уровня 10, и разместить ордер на продажу, если она находится выше уровня 50 индикатора Aroon.

Downline < 10 ==> покупка

Downline > 50 ==> продажа


Торговые системы Aroon

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

В глобальной области MQL5 задайте свойства индикаторов с помощью препроцессора свойств.

//properties of the indicator
#property indicator_separate_window // the place of the indicator
#property indicator_buffers 2 // number of buffers
#property indicator_plots 2 // number of plots

//up line
#property indicator_type1  DRAW_LINE      // type of the up values to be drawn is a line
#property indicator_color1 clrGreen       // up line color
#property indicator_style1 STYLE_DASH     // up line style
#property indicator_width1 2              // up line width
#property indicator_label1 "Up"           // up line label

// down line
#property indicator_type2  DRAW_LINE      // type of the down values to be drawn is a line
#property indicator_color2 clrRed         // down line color
#property indicator_style2 STYLE_DASH     // down line style
#property indicator_width2 2              // down line width
#property indicator_label2 "Down"         // down line label

// drawing some levels to be used later 10 and 50
#property indicator_level1 10.0
#property indicator_level2 50.0
#property indicator_levelcolor clrSilver
#property indicator_levelstyle STYLE_DOT

Создание двух целочисленных входных данных для индикатора: периода и горизонтального сдвига с помощью ключевого слова input.

//inputs
input int                      periodInp = 25; // Period
input int                      shiftInp  = 0;  // horizontal shift

Создание двух двойных массивов для значений up и down индикатора.

//buffers of the indicator
double                         upBuffer[];
double                         downBuffer[];

В OnInit() при использовании функции SetIndexBuffer для связи индикаторных буферов с двойными массивами параметры следующие:

  • index - чтобы указать индекс буфера, мы будем использовать 0 для upBuffer и 1 для downBuffer.
  • buffer[] - для указания массива мы будем использовать массивы upBuffer и downBuffer.
  • data_type - чтобы указать тип данных, который нам нужно сохранить (это может быть один из ENUM_INDEXBUFFR_TYPE), мы будем использовать INDICATOR_DATA как для up, так и для down.
   SetIndexBuffer(0, upBuffer, INDICATOR_DATA);
   SetIndexBuffer(1, downBuffer, INDICATOR_DATA);

Установка значений соответствующего свойства и соответствующих индикаторных линий up и down с помощью функции PlotIndexSetInteger с использованием варианта вызова с указанием идентификатора свойства и параметров включает в себя:

  • plot_index - целочисленное значение индекса стиля отображения, оно будет равно 0 для up и 1 - для down.
  • prop_id:: - целое значение идентификатора свойства, оно может быть одним из ENUM_PLOT_PROPERTY_INTEGER. Мы будем использовать PLOT_SHIFT и PLOT_DRAW_BEGIN для up и down.
  • prop_value - целочисленное значение, shiftInp и periodInp для up и down.
   PlotIndexSetInteger(0, PLOT_SHIFT, shiftInp);
   PlotIndexSetInteger(1, PLOT_SHIFT, shiftInp);
   PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, periodInp);
   PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, periodInp);

Установка флага AS_SERIES для массивов up и down

   ArraySetAsSeries(upBuffer, true);
   ArraySetAsSeries(downBuffer, true);

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

   string indicatorName = StringFormat("Aroon Indicator (%i,%i) - ", periodInp, shiftInp);
   IndicatorSetString(INDICATOR_SHORTNAME, indicatorName);
   IndicatorSetInteger(INDICATOR_DIGITS, 0);

Возвращаем INIT_SUCCEEDED как часть события OnInit().

return INIT_SUCCEEDED;

Событие OnCalculate,

int OnCalculate(const int       rates_total,
                const int       prev_calculated,
                const datetime &time[],
                const double   &open[],
                const double   &high[],
                const double   &low[],
                const double   &close[],
                const long     &tick_volume[],
                const long     &volume[],
                const int      &spread[])

В теле события рассчитаем индикатор, возвращая 0, если данных недостаточно.

   if(rates_total < periodInp - 1)
      return (0);

Создание целочисленной переменной счетчика и вычисление ее как результата вычитания rate_total и prev_calculated.

int count = rates_total - prev_calculated;

Если prev_calculated больше 0, что означает, что у нас есть новые данные, обновим счетчик, добавив 1.

   if(prev_calculated > 0)
      count++;

Создадим еще одно условие для обновления значения счетчика

   if(count > (rates_total - periodInp + 1))
      count = (rates_total - periodInp + 1);

Создание цикла for для расчета и обновления значений индикатора up и down после расчета самого высокого и самого низкого значений.

   for(int i = count - 1; i >= 0; i--)
     {
      int highestVal   = iHighest(Symbol(), Period(), MODE_HIGH, periodInp, i);
      int lowestVal    = iLowest(Symbol(), Period(), MODE_LOW, periodInp, i);
      upBuffer[i]   = (periodInp - (highestVal - i)) * 100 / periodInp;
      downBuffer[i] = (periodInp - (lowestVal - i)) * 100 / periodInp;
     }

Возврат rate_total как часть события OnCalculate

return (rates_total);

Итак, ниже приведен полный код для создания нашего пользовательского индикатора Aroon в одном блоке кода.

//+------------------------------------------------------------------+
//|                                                        Aroon.mq5 |
//+------------------------------------------------------------------+
#property indicator_separate_window // the place of the indicator
#property indicator_buffers 2 // number of buffers
#property indicator_plots 2 // number of plots
#property indicator_type1  DRAW_LINE      // type of the up values to be drawn is a line
#property indicator_color1 clrGreen       // up line color
#property indicator_style1 STYLE_DASH     // up line style
#property indicator_width1 2              // up line width
#property indicator_label1 "Up"           // up line label
#property indicator_type2  DRAW_LINE      // type of the down values to be drawn is a line
#property indicator_color2 clrRed         // down line color
#property indicator_style2 STYLE_DASH     // down line style
#property indicator_width2 2              // down line width
#property indicator_label2 "Down"         // down line label
#property indicator_level1 10.0
#property indicator_level2 50.0
#property indicator_levelcolor clrSilver
#property indicator_levelstyle STYLE_DOT
input int periodInp = 25; // Period
input int shiftInp  = 0;  // horizontal shift
double    upBuffer[];
double    downBuffer[];
int OnInit()
  {
   SetIndexBuffer(0, upBuffer, INDICATOR_DATA);
   SetIndexBuffer(1, downBuffer, INDICATOR_DATA);
   PlotIndexSetInteger(0, PLOT_SHIFT, shiftInp);
   PlotIndexSetInteger(1, PLOT_SHIFT, shiftInp);
   PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, periodInp);
   PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, periodInp);
   ArraySetAsSeries(upBuffer, true);
   ArraySetAsSeries(downBuffer, true);
   string indicatorName = StringFormat("Aroon Indicator (%i,%i) - ", periodInp, shiftInp);
   IndicatorSetString(INDICATOR_SHORTNAME, indicatorName);
   IndicatorSetInteger(INDICATOR_DIGITS, 0);
   return INIT_SUCCEEDED;
  }
int OnCalculate(const int       rates_total,
                const int       prev_calculated,
                const datetime &time[],
                const double   &open[],
                const double   &high[],
                const double   &low[],
                const double   &close[],
                const long     &tick_volume[],
                const long     &volume[],
                const int      &spread[])
  {
   if(rates_total < periodInp - 1)
      return (0);
   int count = rates_total - prev_calculated;
   if(prev_calculated > 0)
      count++;
   if(count > (rates_total - periodInp + 1))
      count = (rates_total - periodInp + 1);
   for(int i = count - 1; i >= 0; i--)
     {
      int highestVal   = iHighest(Symbol(), Period(), MODE_HIGH, periodInp, i);
      int lowestVal    = iLowest(Symbol(), Period(), MODE_LOW, periodInp, i);
      upBuffer[i]   = (periodInp - (highestVal - i)) * 100 / periodInp;
      downBuffer[i] = (periodInp - (lowestVal - i)) * 100 / periodInp;
     }
   return (rates_total);
  }
//+------------------------------------------------------------------+

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

 Aroon ind

Индикатор готов и мы можем создавать наши торговые стратегии. Итак, мы начнем с пересечения линий Aroon, а затем перейдем к уровням, но перед этим мы создадим простую программу, которая сможет отображать значения Aroon up и down. Следующий метод позволяет сделать это:

Сначала в глобальной области мы создадим два пользовательских входных параметра Period и Shift, используя ключевое слово input.

input int         periodInp = 25; // Period
input int         shiftInp  = 0; // Shift

Объявим целочисленную переменную для Aroon, чтобы позже присвоить ей хэндл индикатора.

int aroon;

В OnInit() назначим функцию iCustom для прикрепления или возврата хэндла созданного пользовательского индикатора Aroon в советник. Параметры следующие:

  • Symbol - имя символа, мы будем использовать _Symbol для возврата текущего.
  • period - период, мы будем использовать _Period для возврата текущего.
  • name - точное имя пользовательского индикатора с указанием его точного пути в папке Indicators.
  • Затем укажем список входных параметров пользовательского индикатора. Мы будем использовать только два созданных нами входных параметра (Period и Shift).
aroon = iCustom(_Symbol,PERIOD_CURRENT,"Aroon",periodInp,shiftInp);

Затем возвращаем (INIT_SUCCEEDED), когда советник будет успешно инициализирован.

return(INIT_SUCCEEDED);

В OnDeinit напечатаем "EA is removed" (советник удален), используя ключевое слово Print, когда происходит событие Deinit для деинициализации работающей программы MQL5.

void OnDeinit(const int reason)
  {
   Print("EA is removed");
  }

В событии OnTick() объявим два массива double - upBuffer и downBuffer

double upBuffer[], downBuffer[];

Получение данных созданных буферов индикатора Aroon с помощью функции CopyBuffer с вариантом вызова по первой позиции и количеству необходимых элементов и параметров:

  • indicator_handle - хэндл пользовательского индикатора Aroon.
  • buffer_num - номер буфера индикатора.
  • start_pos - позиция начала отсчета.
  • count - количество счетчиков, начиная с start_pos.
  • buffer[] - целевой массив.
   CopyBuffer(aroon,0,0,3,upBuffer);
   CopyBuffer(aroon,1,0,3,downBuffer);

Использование ArraySetAsSeries для установки флага AS_SERIES в указанный флаг, который будет верным для обратного порядка индексации массивов.

   ArraySetAsSeries(upBuffer,true);
   ArraySetAsSeries(downBuffer,true);

Объявление двух двойных переменных upValue и downValue для присвоения текущих значений индикатора Aroon из массивов путем индексации [0]

   double upValue = upBuffer[0];
   double downValue = downBuffer[0];

Использование функции Comment для вывода комментария на графике со значениями индикатора up и down

Comment("upValue: ",upValue,"\ndownValue: ",downValue);

Ниже приведен полный код в одном блоке:

//+------------------------------------------------------------------+
//|                                                AroonValuesEA.mq5 |
//+------------------------------------------------------------------+
input int         periodInp = 25; // Period
input int         shiftInp  = 0; // Shift
int aroon;
int OnInit()
  {
   aroon = iCustom(_Symbol,PERIOD_CURRENT,"Aroon",periodInp,shiftInp);
   return(INIT_SUCCEEDED);
  }
void OnDeinit(const int reason)
  {
   Print("EA is removed");
  }
void OnTick()
  {
   double upBuffer[], downBuffer[];
   CopyBuffer(aroon,0,0,3,upBuffer);
   CopyBuffer(aroon,1,0,3,downBuffer);
   ArraySetAsSeries(upBuffer,true);
   ArraySetAsSeries(downBuffer,true);
   double upValue = upBuffer[0];
   double downValue = downBuffer[0];
   Comment("upValue: ",upValue,"\ndownValue: ",downValue);
  }
//+------------------------------------------------------------------+

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

AroonValues

Как мы видим на предыдущем графике, значения up и down указаны в виде комментария. Пользовательский индикатор запущен на графике, чтобы убедиться, что советник возвращает те же значения индикатора (96, 48).

Стратегия пересечения:

Теперь пришло время реализовать упомянутые нами торговые стратегии в коде. Начнем со стратегии пересечения.

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

#include <trade/trade.mqh>

Создадим пять входных переменных: period, horizontal shift, lotSize, slLvl и tpLvl, и назначим значения по умолчанию для каждого

input int         periodInp = 25; // Period
input int         shiftInp  = 0; // Shift
input double      lotSize=1;
input double      slLvl=200;
input double      tpLvl=600;

Создадим следующие переменные:

  • Целочисленная переменная Aroon, которая будет использоваться позже для определения индикатора.
  • Целочисленная переменная barstotal используется для ограничения открытия ордеров для каждого бара.
  • Торговый объект CTrade, который будет использоваться при размещении ордеров.
int aroon;
int barsTotal;
CTrade trade;

В событии OnInit() мы определим объявленную переменную barsTotal с помощью функций iBars, которые возвращают доступные бары символа и периода в истории.

barsTotal=iBars(_Symbol,PERIOD_CURRENT);

Определим переменную Aroon с помощью iCustom для включения созданного нами пользовательского индикатора Aroon.

aroon = iCustom(_Symbol,PERIOD_CURRENT,"Aroon",periodInp,shiftInp);

В событии OnDeinit() напечатаем уведомление об удалении советника.

Print("EA is removed");

В событии OnTick() объявим целочисленную переменную bars для хранения количества баров для каждого тика

int bars=iBars(_Symbol,PERIOD_CURRENT);

Проверим barsTotal и bars на равенство

if(barsTotal != bars)

Затем обновим barsTotal с помощью буферов bars.

barsTotal=bars;

Объявим два double-массива up и down, получим данные из буферов индикатора, установим флага AS_SERIES для выбранного массива, объявим и определим четыре двойные переменные для предыдущих и текущих значений up и down.

      double upBuffer[], downBuffer[];
      CopyBuffer(aroon,0,0,3,upBuffer);
      CopyBuffer(aroon,1,0,3,downBuffer);
      ArraySetAsSeries(upBuffer,true);
      ArraySetAsSeries(downBuffer,true);
      double prevUpValue = upBuffer[1];
      double prevDownValue = downBuffer[1];
      double upValue = upBuffer[0];
      double downValue = downBuffer[0];

Затем установим условия ордера на покупку, которые заключаются в том, что prevUpValue меньше, чем prevDownValue, и в то же время upValue больше, чем downValue.

if(prevUpValue<prevDownValue && upValue>downValue)

Когда это условие выполнено, объявим double-переменную ask и ее текущую цену ask текущего символа, также объявим и укажем slVal и tpVal и разместим позиции на покупку с предопределенным пользовательским значением lotSize на текущем символе. По текущей цене ask стоп-лосс будет таким же, как и предопределенный для slVal, а тейк-профит будет таким же, как и для tpVal.

         double ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
         double slVal=ask - slLvl*_Point;
         double tpVal=ask + tpLvl*_Point;
         trade.Buy(lotSize,_Symbol,ask,slVal,tpVal);

Затем установим условия ордера на продажу, которые заключаются в том, что prevUpValue превышает prevDownValue, и в то же время upValue меньше, чем downValue.

if(prevUpValue>prevDownValue && upValue<downValue)
Когда это условие выполнено, объявим double-переменную bid и ее текущую цену bid текущего символа, также объявим и укажем slVal и tpVal и разместим позиции на продажу с предопределенным пользовательским значением lotSize на текущем символе. По текущей цене bid стоп-лосс будет таким же, как и предопределенный для slVal, а тейк-профит будет таким же, как и для tpVal.
         double bid = SymbolInfoDouble(_Symbol,SYMBOL_BID);
         double slVal=bid + slLvl*_Point;
         double tpVal=bid - tpLvl*_Point;
         trade.Sell(lotSize,_Symbol,bid,slVal,tpVal);

Ниже приведен весь код стратегии пересечения Aroon в одном блоке:

//+------------------------------------------------------------------+
//|                                             AroonCrossoverEA.mq5 |
//+------------------------------------------------------------------+
#include <trade/trade.mqh>
input int         periodInp = 25; // Period
input int         shiftInp  = 0; // Shift
input double      lotSize=1;
input double      slLvl=200;
input double      tpLvl=600;
int aroon;
int barsTotal;
CTrade trade;
int OnInit()
  {
   barsTotal=iBars(_Symbol,PERIOD_CURRENT);
   aroon = iCustom(_Symbol,PERIOD_CURRENT,"Aroon",periodInp,shiftInp);
   return(INIT_SUCCEEDED);
  }
void OnDeinit(const int reason)
  {
   Print("EA is removed");
  }
void OnTick()
  {
   int bars=iBars(_Symbol,PERIOD_CURRENT);
   if(barsTotal != bars)
     {
      barsTotal=bars;
      double upBuffer[], downBuffer[];
      CopyBuffer(aroon,0,0,3,upBuffer);
      CopyBuffer(aroon,1,0,3,downBuffer);
      ArraySetAsSeries(upBuffer,true);
      ArraySetAsSeries(downBuffer,true);
      double prevUpValue = upBuffer[1];
      double prevDownValue = downBuffer[1];
      double upValue = upBuffer[0];
      double downValue = downBuffer[0];
      if(prevUpValue<prevDownValue && upValue>downValue)
        {
         double ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
         double slVal=ask - slLvl*_Point;
         double tpVal=ask + tpLvl*_Point;
         trade.Buy(lotSize,_Symbol,ask,slVal,tpVal);
        }
      if(prevUpValue>prevDownValue && upValue<downValue)
        {
         double bid = SymbolInfoDouble(_Symbol,SYMBOL_BID);
         double slVal=bid + slLvl*_Point;
         double tpVal=bid - tpLvl*_Point;
         trade.Sell(lotSize,_Symbol,bid,slVal,tpVal);
        }
     }
  }
//+------------------------------------------------------------------+

После успешной компиляции кода мы можем найти примеры размещения ордеров на основе следующей стратегии:

Пример ордера на покупку:

покупка

Как мы видим в предыдущем примере, у нас есть ордер на покупку после пересечения линий up и down.

Пример ордера на продажу:

продажа

Как мы видим в предыдущем примере, у нас есть ордер на продажу после того, как линия down пересеклась с линией up.

Стратегия уровней:

В этой части мы реализуем стратегию уровней Aroon, которая позволит советнику открывать ордер на основе пересечения линии down с уровнями 10 и 50 самого индикатора Aroon. Ниже показано, как мы можем реализовать эту стратегию в MQL5. Код довольно похож на тот, что был реализован для стратегии пересечения, поэтому я приведу весь код и подчеркну различия.

Ниже приведен полный код для кодирования стратегии уровней Aroon в одном блоке кода:

//+------------------------------------------------------------------+
//|                                                AroonLevelsEA.mq5 |
//+------------------------------------------------------------------+
#include <trade/trade.mqh>
input int         periodInp = 25; // Period
input int         shiftInp  = 0; // Shift
input double      lotSize=1;
input double      slLvl=200;
input double      tpLvl=600;
int aroon;
int barsTotal;
CTrade trade;
int OnInit()
  {
   barsTotal=iBars(_Symbol,PERIOD_CURRENT);
   aroon = iCustom(_Symbol,PERIOD_CURRENT,"Aroon",periodInp,shiftInp);
   return(INIT_SUCCEEDED);
  }
void OnDeinit(const int reason)
  {
   Print("EA is removed");
  }
void OnTick()
  {
   int bars=iBars(_Symbol,PERIOD_CURRENT);
   if(barsTotal != bars)
     {
      barsTotal=bars;
      double upBuffer[], downBuffer[];
      CopyBuffer(aroon,0,0,3,upBuffer);
      CopyBuffer(aroon,1,0,3,downBuffer);
      ArraySetAsSeries(upBuffer,true);
      ArraySetAsSeries(downBuffer,true);
      double prevDownValue = downBuffer[1];
      double downValue = downBuffer[0];
      if(prevDownValue> 10 && downValue<10)
        {
         double ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
         double slVal=ask - slLvl*_Point;
         double tpVal=ask + tpLvl*_Point;
         trade.Buy(lotSize,_Symbol,ask,slVal,tpVal);
        }
      if(prevDownValue < 50 && downValue>50)
        {
         double bid = SymbolInfoDouble(_Symbol,SYMBOL_BID);
         double slVal=bid + slLvl*_Point;
         double tpVal=bid - tpLvl*_Point;
         trade.Sell(lotSize,_Symbol,bid,slVal,tpVal);
        }
     }
  }

Отличия в коде:

Нам нужно только определить предыдущие и текущие значения

      double prevDownValue = downBuffer[1];
      double downValue = downBuffer[0];

Условие стратегии: если prevDownValue больше уровня 10 и в то же время текущее значение downValue меньше уровня 10. Нам нужно, чтобы советник разместил ордер на покупку после определения ask, стоп-лосса и тейк-профита.

      if(prevDownValue> 10 && downValue<10)
        {
         double ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
         double slVal=ask - slLvl*_Point;
         double tpVal=ask + tpLvl*_Point;
         trade.Buy(lotSize,_Symbol,ask,slVal,tpVal);
        }

Если prevDownValue меньше уровня 50 и в то же время текущее значение downValue больше уровня 50. Нам нужно, чтобы советник разместил ордер на продажу после определения текущего bid, стоп-лосса и тейк-профита.

      if(prevDownValue < 50 && downValue>50)
        {
         double bid = SymbolInfoDouble(_Symbol,SYMBOL_BID);
         double slVal=bid + slLvl*_Point;
         double tpVal=bid - tpLvl*_Point;
         trade.Sell(lotSize,_Symbol,bid,slVal,tpVal);
        }

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

Пример ордера на покупку:

покупка

Пример ордера на продажу:

продажа


Тестирование торговой системы Aroon

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

Мы сосредоточимся на следующих ключевых измерениях, чтобы провести сравнение между ними:

  • Чистая прибыль (Net Profit) - рассчитывается путем вычитания валового убытка из валовой прибыли. Чем выше значение, тем лучше.
  • Относительная просадка по балансу (Balance DD relative) - максимальный убыток на счете во время работы. Чем ниже значение, тем лучше.
  • Профит-фактор (Profit factor) - отношение валовой прибыли к валовому убытку. Чем выше значение, тем лучше.
  • Матожидание выигрыша (Expected payoff) - средняя прибыль или убыток сделки. Чем выше значение, тем лучше.
  • Фактор восстановления (Recovery factor) - определяет, насколько хорошо протестированная стратегия восстанавливается после потерь. Чем выше значение, тем лучше.
  • Коэффициент Шарпа (Sharpe Ratio) - определяет риск и стабильность тестируемой торговой системы путем сравнения доходности с безрисковой доходностью. Чем выше значение, тем лучше.

Мы также будем тестировать один и тот же период при тестировании обеих стратегий. Период составляет один год с 1 января 2023 года по 31 декабря 2023 года, мы протестируем два таймфрейма: 15 минут и один час.

Стратегия пересечения:

Теперь посмотрим на результаты стратегии пересечения Aroon на двух таймфреймах - 15 минут и 1 час, чтобы увидеть, какой из них лучше, исходя из ранее упомянутых цифр.

Тестирование стратегии на 15-минутном таймфрейме:

Результаты представлены на графиках ниже:

результаты теста 15m

результаты теста3- 15m

результаты теста2- 15m

Основываясь на предыдущих результатах, мы получаем следующие цифры:

  • Чистая прибыль: 14791
  • Относительная просадка по балансу: 6,78%
  • Профит-фактор: 1,17
  • Матожидание: 24,53
  • Фактор восстановления: 1,91
  • Коэффициент Шарпа: 2,23

Тестирование стратегии на часовом таймфрейме:

Результаты представлены на графиках ниже:

результаты теста 1hbr>

результаты теста3- 1h

результаты теста2- 1h

Основываясь на предыдущих результатах, мы получаем следующие цифры:

  • Чистая прибыль: 6242,20
  • Относительная просадка по балансу: 1,80%
  • Профит-фактор: 1,39
  • Матожидание: 53,81
  • Фактор восстановления: 2,43
  • Коэффициент Шарпа: 3,23

Стратегия уровней:

Здесь мы протестируем стратегию уровней Aroon на двух таймфреймах - 15 минут и 1 час, - чтобы сравнить одни и те же цифры для обоих двух таймфреймов.

Тестирование стратегии на 15-минутном таймфрейме:

Результаты представлены на графиках ниже:

результаты теста 15m

результаты теста3- 15m

результаты теста2- 15m

Основываясь на предыдущих результатах, мы получаем следующие цифры:

  • Чистая прибыль: 42417,30
  • Относительная просадка по балансу: 12,91%
  • Профит-фактор: 1,21
  • Матожидание: 29,62
  • Фактор восстановления: 2,27
  • Коэффициент Шарпа: 1,88

Тестирование стратегии на часовом таймфрейме:

Результаты представлены на графиках ниже:

результаты теста 1h

результаты теста3- 1h

результаты теста2- 1h

Основываясь на предыдущих результатах, мы получаем следующие цифры:

  • Чистая прибыль: 16001,10
  • Относительная просадка по балансу: 5,11%
  • Профит-фактор: 1,30
  • Матожидание: 41,89
  • Фактор восстановления: 2,68
  • Коэффициент Шарпа: 2,61

В таблице ниже все результаты собраны в одном месте для лучшего сравнения:

значения

Основываясь на вышеизложенном, мы можем найти наилучшие значения, соответствующие протестированной стратегии и таймфрейму:

  • Чистая прибыль: Наилучший показатель (42417,30 USD) получен при использовании стратегии уровней при тестировании на 15-минутном таймфрейме.
  • Относительная просадка по балансу: Наилучший показатель (1,80%) получен при использовании стратегии пересечения при тестировании на часовом таймфрейме.
  • Профит-фактор: Наилучший показатель (1,39) получен при использовании стратегии пересечения при тестировании на часовом интервале.
  • Матожидание: Наилучшее значение (53,81) получено при использовании стратегии пересечения при тестировании на часовом интервале.
  • Фактор восстановления: Наилучшее значение (2,68) получено при использовании стратегии уровней при тестировании на часовом таймфрейме.
  • Коэффициент Шарпа: Наилучшее значение (3,23) получено со стратегией пересечения при тестировании на часовом интервале.

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


Заключение

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

Мы подробно описали индикатор Aroon, а также его применение и расчет. Мы также рассмотрели две простые стратегии, которые можно использовать:

  • Стратегия пересечения позволяет нам автоматически размещать позицию на покупку, когда линия Aroon Up находится выше Aroon Down, или позицию на продажу, когда линия Aroon Down находится выше Aroon Up.
  • Стратегия уровней позволяет нам автоматически разместить позицию на покупку, если линия Aroon Down ниже уровня 10 индикатора, или позицию на продажу, если Aroon Down находится выше уровня 50.

Мы реализовали эти стратегии в коде, создав советник для каждой из них. После создания нашего пользовательского индикатора Aroon на MQL5 и написания простой программы, которая может генерировать значения Aroon Up и Aroon Down на графике, мы запустили индикатор на графике, протестировали его и определили важные цифры по результатам тестирования каждой стратегии на двух таймфреймах - 15 минут и 1 час. Мы можем использовать их в зависимости от наших торговых целей и результатов каждой стратегии.

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

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

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

Прикрепленные файлы |
Aroon.mq5 (3.04 KB)
AroonValuesEA.mq5 (0.91 KB)
AroonLevelsEA.mq5 (1.63 KB)
Создаем простой мультивалютный советник с использованием MQL5 (Часть 6): Два индикатора RSI пересекают линии друг друга Создаем простой мультивалютный советник с использованием MQL5 (Часть 6): Два индикатора RSI пересекают линии друг друга
Под мультивалютным советником в этой статье понимается советник, или торговый робот, который использует два индикатора RSI с пересекающимися линиями - быстрый RSI, который пересекается с медленным.
Разрабатываем мультивалютный советник (Часть 11): Начало автоматизации процесса оптимизации Разрабатываем мультивалютный советник (Часть 11): Начало автоматизации процесса оптимизации
Для получения хорошего советника нам надо подобрать для него множество хороших наборов параметров экземпляров торговых стратегий. Это можно делать вручную, запуская оптимизацию на разных символах, и затем отбирая лучшие результаты. Но лучше поручить эту работу программе и заняться более продуктивной деятельностью.
Нейросети — это просто (Часть 91): Прогнозирование в частотной области (FreDF) Нейросети — это просто (Часть 91): Прогнозирование в частотной области (FreDF)
Мы продолжаем рассмотрение темы анализ и прогнозирования временных рядов в частотной области. И в данной статье мы познакомимся с новым методом прогнозирования в частотной области, который может быть добавлен к многим, изученным нами ранее, алгоритмам.
Как сделать любой тип Trailing Stop и подключить к советнику Как сделать любой тип Trailing Stop и подключить к советнику
В статье рассмотрим классы для удобного создания различных трейлингов. Научимся подключать трейлинг-стоп к любому советнику.