English 中文 Español Deutsch 日本語 Português
preview
Разработка пользовательского индикатора True Strength Index с помощью MQL5

Разработка пользовательского индикатора True Strength Index с помощью MQL5

MetaTrader 5Трейдинг | 8 сентября 2023, 09:52
1 332 0
Mohamed Abdelmaaboud
Mohamed Abdelmaaboud

Введение

Технические индикаторы могут быть очень полезны при правильном использовании, поскольку они могут дать дополнительную информацию, которую трудно обнаружить, просто наблюдая за ценовым действием. Существует множество готовых технических индикаторов, которые мы можем использовать, но иногда нам нужно настроить их, чтобы они давали нам конкретную информацию, либо нам приходится создавать новый индикатор, основанный на наших идеях. Существует способ создать такие индивидуальные индикаторы в MQL5 и использовать их в торговой платформе MetaTrader 5. В этой статье я покажу, как создать индикатор True Strength Index с нуля. Мы изучим специфику этого индикатора и посмотрим, как его рассчитать в нашем коде. Также мы узнаем, как мы можем использовать этот пользовательский индикатор в торговой системе, создав советника. Все эти вопросы будут рассмотрены в следующих разделах:

Освоив упомянутые темы, мы сможем использовать и интерпретировать индикатор True Strength Index, а также рассчитать и закодировать его как пользовательский индикатор на языке MQL5 для использования в MetaTrader 5. Вы также сможете реализовать индикатор в других торговых системах или советниках. Если вы хотите развить свои навыки программирования, я советую вам писать код самостоятельно, поскольку эта практика является очень важным шагом в любом процессе обучения. Мы будем использовать MetaTrader 5 для написания кода MQL5 в его IDE, встроенной в торговый терминал MetaTrader 5. Если у вас нет платформы или вы не знаете, как ее скачать и использовать, ознакомьтесь с разделом "Как написать MQL5-код в редакторе MetaEditor" в одной из моих предыдущих статей.

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


Определение True Strength Index (TSI)

В этом разделе мы рассмотрим технический индикатор True Strength Index (TSI). Он был разработан Уильямом Блау. Индикатор измеряет импульс ценового действия, то есть силу инструмента. Он колеблется вокруг нулевой линии, поэтому является импульсным осциллятором. Вместе с ним можно использовать сигнальную линию для получения дополнительных сигналов покупки или продажи на основе пересечения этих линий. Однако мы можем получить сигналы только по линии TSI - по ее пересечению с нулевым уровнем. Если она выше нулевой линии, это означает бычий импульс, а если ниже - медвежий. Индикатор можно использовать для обнаружения областей перекупленности и перепроданности, а также для обнаружения бычьих и медвежьих расхождений. Поскольку мы знаем, что нам необходимо подтверждать его сигналы, чтобы увеличить вес доказательств, лучше использовать его в сочетании с другими техническими инструментами, которые мы должны использовать в том же контексте ценового действия для лучшего понимания.

Теперь разберемся, как рассчитать этот индикатор. Расчет выполняется в несколько этапов, а именно:

Расчет дважды сглаженного импульса:

  • Расчет импульса (изменения цены) путем вычитания предыдущей цены из текущей
  • Расчет первого сглаживания путем получения 25-периодной EMA рассчитанного импульса
  • Расчет второго сглаживания путем получения 13-периодной EMA первого сглаживания (25-периодной EMA рассчитанного импульса)

Расчет дважды сглаженного абсолютного импульса:

  • Расчет абсолютного импульса путем вычитания абсолютной предыдущей цены из абсолютной текущей
  • Расчет первого сглаживания путем получения 25-периодной EMA рассчитанного абсолютного импульса
  • Расчет второго сглаживания путем получения 13-периодной EMA первого сглаживания (25-периодной EMA рассчитанного абсолютного импульса)

Расчет TSI = 100*(Двойной сглаженный импульс / Двойной сглаженный абсолютный импульс)

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


Пользовательский индикатор Simple TSI

Язык программирования MQL5 имеет множество предопределенных технических индикаторов, и мы можем использовать их в наших системах, используя предопределенную функцию. Мы уже упоминали много таких индикаторов в предыдущих статьях серии, обсуждая, как мы можем разработать торговую систему. Вы можете посмотреть предыдущие статьи и, возможно, найти что-то полезное. Теперь вопрос в том, как мы можем создать индикатор, если он не существует в стандартном пакете поставки платформы, а даже если он существует, как мы можем создать пользовательский индикатор для получения желаемых сигналов или триггеров. Короткий ответ — создать собственный индикатор, используя основной язык программирования. Это то, чем мы и займемся здесь.

Мы научимся создавать пользовательский индикатор True Strength Index с помощью MQL5. Затем мы будем использовать его возможности в других системах или советниках. Следующие шаги предназначены для создания этого пользовательского индикатора.

Создавая дополнительные параметры с помощью #property, рядом мы указываем значение идентификатора. Нам необходимо указать следующие параметры:

  • (indicator_separate_window) — показывать индикатор в отдельном окне.
  • (indicator_buffers) — количество буферов индикатора. Укажем (8).
  • (indicator_plots) — указать количество графических серий индикатора. Укажем (1).
  • (indicator_label1) — для установки метки номера графической серии укажем (TSI).
  • (indicator_type1) — для указания типа графического построения путем указания значения из значений ENUM_DRAW_TYPE укажем (DRAW_LINE).
  • (indicator_color1) — чтобы указать цвет отображаемой линии индикатора, укажем (clrBlue).
  • (indicator_style1) — для указания стиля линии индикатора укажем (STYLE_SOLID).
  • (indicator_width1) — для указания толщины линии индикатора укажем (3).
#property indicator_separate_window
#property indicator_buffers 8
#property indicator_plots   1
#property indicator_label1  "TSI"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrBlue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  3

Нам необходимо включить файл MovingAverage.mqh, чтобы использовать его компонент в наших расчетах. Этот файл активируется в Include с помощью команды #include. Убедитесь, что имена файлов совпадают.

#include <MovingAverages.mqh>

Нам необходимо установить два периода сглаживания, которые мы будем использовать при расчете индикатора, используя класс входных данных для ввода этих значений пользователем, если ему необходимо обновить значения по умолчанию, которые указаны в программе. После этого мы определим тип данных переменных (InpSmPeriod1, InpSmPeriod2), которые нам нужно объявить, используя uint, который представляет собой целое число без знака. Затем назначим (25) InpSmPeriod1 и (13) InpSmPeriod2 в качестве значений по умолчанию. 

input uint     InpSmPeriod1   =  25;    // Smoothing period 1
input uint     InpSmPeriod2   =  13;   // Smoothing period 2

Создаем две целочисленные переменные для периодов сглаживания (smperiod1,smperiod2).

int            smperiod1;
int            smperiod2;

Создаем семь массивов для индикаторных буферов

double         indBuff[];
double         momBuff[];
double         momSmBuff1[];
double         momSmBuff2[];
double         absMomBuff[];
double         absMomSmBuff1[];
double         absMomSmBuff2[];

Выполним следующие шаги внутри функции OnInit ():

Объявим переменные (smperiod1,smperiod2), вернув значение 2, если пользовательские входные параметры InpSmPeriod1 и InpSmPeriod2 меньше 2, или вернув значения InpSmPeriod1 и InpSmPeriod2 в противном случае.

   smperiod1=int(InpSmPeriod1<2 ? 2 : InpSmPeriod1);
   smperiod2=int(InpSmPeriod2<2 ? 2 : InpSmPeriod2);

Свяжем индикаторные буферы с массивами с помощью функции (SetIndexBuffer). Параметры такие:

index: номер индикаторного буфера и чисел от 0 до 7 в программе.

buffer[]: массив, объявленный в пользовательском индикаторе.

data_type: тип данных, хранящихся в массиве индикаторов.

   SetIndexBuffer(0,indBuff,INDICATOR_DATA);
   SetIndexBuffer(2,momBuff,INDICATOR_CALCULATIONS);
   SetIndexBuffer(3,momSmBuff1,INDICATOR_CALCULATIONS);
   SetIndexBuffer(4,momSmBuff2,INDICATOR_CALCULATIONS);
   SetIndexBuffer(5,absMomBuff,INDICATOR_CALCULATIONS);
   SetIndexBuffer(6,absMomSmBuff1,INDICATOR_CALCULATIONS);
   SetIndexBuffer(7,absMomSmBuff2,INDICATOR_CALCULATIONS);

Задавая значение соответствующего свойства индикатора, это свойство индикатора (значение prop) должно быть строкового типа с помощью функции (IndicatorSetString) с вариантом вызова с указанием только идентификатора свойства. Этот шаг предназначен для установки короткого имени индикатора и определения периодов, которые будут отображаться в верхней левой части окна индикатора. Его параметры:

  • prop_id: идентификатор свойства индикатора, входящего в перечисление (ENUM_CUSTOMIND_PROPERTY_STRING). В нашей программе это будет (INDICATOR_SHORTNAME).
  • prop_value: значение свойства, которое будет строковым типом данных. В нашем случае это "True Strength Index ("+(string)smperiod1+","+(string)smperiod2+")".
IndicatorSetString(INDICATOR_SHORTNAME,"True Strength Index ("+(string)smperiod1+","+(string)smperiod2+")");

Задаем другое значение свойства индикатора в целочисленном типе данных для нормализации значения индикатора по числу знаков после запятой с помощью (IndicatorSetInteger) с вариантом вызова с указанием только идентификатора свойства. Параметры: 

  • prop_id: идентификатор свойства индикатора, входящего в перечисление (ENUM_CUSTOMIND_PROPERTY_INTEGER). В нашей программе это будет (INDICATOR_DIGITS).
  • prop_value: значение свойства, которое будет целочисленным типом данных. Это Digits().
IndicatorSetInteger(INDICATOR_DIGITS,Digits());

Устанавливаем флаг AS_SERIES для массива с помощью (ArraySetAsSeries).

   ArraySetAsSeries(indBuff,true);
   ArraySetAsSeries(momBuff,true);
   ArraySetAsSeries(momSmBuff1,true);
   ArraySetAsSeries(momSmBuff2,true);
   ArraySetAsSeries(absMomBuff,true);
   ArraySetAsSeries(absMomSmBuff1,true);
   ArraySetAsSeries(absMomSmBuff2,true);

После функции OnCalculate

  • Установим флаг AS_SERIES для закрытого массива из OnCalculate, а затем проверим является ли rates_total меньше 2, чтобы вернуть 0.
  • Создадим целочисленную переменную (limit), равную (rates_total-prev_calculated).
  • Проверяем, больше ли предельная переменная 1. В этом случае нам нужно выполнить следующие шаги:
  • Обновим переменную limit с результатом (rates_total - 2).
  • Инициализируем числовые массивы типа double заданным значением с помощью функции (ArrayInitialize). Его параметрами являются array[] для указания числового массива, который должен быть инициализирован, другим параметром является значение для указания нового устанавливаемого значения.
   ArraySetAsSeries(close,true);
   if(rates_total<2)
      return 0;

   int limit=rates_total-prev_calculated;
   if(limit>1)
     {
      limit=rates_total-2;
      ArrayInitialize(indBuff,EMPTY_VALUE);
      ArrayInitialize(momBuff,0);
      ArrayInitialize(momSmBuff1,0);
      ArrayInitialize(momSmBuff2,0);
      ArrayInitialize(absMomBuff,0);
      ArrayInitialize(absMomSmBuff1,0);
      ArrayInitialize(absMomSmBuff2,0);
     }

Создадим цикл для обновления momBuff[i], absMomBuff[i]. Новые функции, которые использовались на этом этапе:

  • операция цикла (for) с тремя выражениями и исполняемым оператором.
  • IsStopped() чтобы проверить, произошло ли принудительное завершение работы mql5-программы.
  • MathAbs возвращает абсолютное значение (модуль), и мы можем использовать функцию febs() для того же результата.
   for(int i=limit; i>=0 && !IsStopped(); i--)
     {
      momBuff[i]=close[i]-close[i+1];
      absMomBuff[i]=MathAbs(momBuff[i]);
     }

Осуществим проверку с помощью функции ExponentialMAOnBuffer из включаемого файла (MovingAverage).

   if(ExponentialMAOnBuffer(rates_total,prev_calculated,0,smperiod1,momBuff,momSmBuff1)==0)
      return 0;
   if(ExponentialMAOnBuffer(rates_total,prev_calculated,0,smperiod1,absMomBuff,absMomSmBuff1)==0)
      return 0;
   if(ExponentialMAOnBuffer(rates_total,prev_calculated,smperiod1,smperiod2,momSmBuff1,momSmBuff2)==0)
      return 0;
   if(ExponentialMAOnBuffer(rates_total,prev_calculated,smperiod1,smperiod2,absMomSmBuff1,absMomSmBuff2)==0)
      return 0;

Создадим еще один цикл для обновления переменной indBuff[i] с помощью функции for

   for(int i=limit; i>=0 && !IsStopped(); i--)
      indBuff[i]=(absMomSmBuff2[i]!=0 ? 100.0*momSmBuff2[i]/absMomSmBuff2[i] : 0);

В конце программы есть функция возврата (rates_total).

   return(rates_total);

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

//+------------------------------------------------------------------+
//|                                                   simple TSI.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 8
#property indicator_plots   1
#property indicator_label1  "TSI"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrBlue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  3
#include <MovingAverages.mqh>
input uint     InpSmPeriod1   =  25;    // Smoothing period 1
input uint     InpSmPeriod2   =  13;   // Smoothing period 2
int            smperiod1;
int            smperiod2;
double         indBuff[];
double         momBuff[];
double         momSmBuff1[];
double         momSmBuff2[];
double         absMomBuff[];
double         absMomSmBuff1[];
double         absMomSmBuff2[];
int OnInit()
  {
   smperiod1=int(InpSmPeriod1<2 ? 2 : InpSmPeriod1);
   smperiod2=int(InpSmPeriod2<2 ? 2 : InpSmPeriod2);
   SetIndexBuffer(0,indBuff,INDICATOR_DATA);
   SetIndexBuffer(2,momBuff,INDICATOR_CALCULATIONS);
   SetIndexBuffer(3,momSmBuff1,INDICATOR_CALCULATIONS);
   SetIndexBuffer(4,momSmBuff2,INDICATOR_CALCULATIONS);
   SetIndexBuffer(5,absMomBuff,INDICATOR_CALCULATIONS);
   SetIndexBuffer(6,absMomSmBuff1,INDICATOR_CALCULATIONS);
   SetIndexBuffer(7,absMomSmBuff2,INDICATOR_CALCULATIONS);
   IndicatorSetString(INDICATOR_SHORTNAME,"True Strength Index ("+(string)smperiod1+","+(string)smperiod2+")");
   IndicatorSetInteger(INDICATOR_DIGITS,Digits());
   ArraySetAsSeries(indBuff,true);
   ArraySetAsSeries(momBuff,true);
   ArraySetAsSeries(momSmBuff1,true);
   ArraySetAsSeries(momSmBuff2,true);
   ArraySetAsSeries(absMomBuff,true);
   ArraySetAsSeries(absMomSmBuff1,true);
   ArraySetAsSeries(absMomSmBuff2,true);
   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[])
  {
   ArraySetAsSeries(close,true);
   if(rates_total<2)
      return 0;

   int limit=rates_total-prev_calculated;
   if(limit>1)
     {
      limit=rates_total-2;
      ArrayInitialize(indBuff,EMPTY_VALUE);
      ArrayInitialize(momBuff,0);
      ArrayInitialize(momSmBuff1,0);
      ArrayInitialize(momSmBuff2,0);
      ArrayInitialize(absMomBuff,0);
      ArrayInitialize(absMomSmBuff1,0);
      ArrayInitialize(absMomSmBuff2,0);
     }
   for(int i=limit; i>=0 && !IsStopped(); i--)
     {
      momBuff[i]=close[i]-close[i+1];
      absMomBuff[i]=MathAbs(momBuff[i]);
     }
   if(ExponentialMAOnBuffer(rates_total,prev_calculated,0,smperiod1,momBuff,momSmBuff1)==0)
      return 0;
   if(ExponentialMAOnBuffer(rates_total,prev_calculated,0,smperiod1,absMomBuff,absMomSmBuff1)==0)
      return 0;
   if(ExponentialMAOnBuffer(rates_total,prev_calculated,smperiod1,smperiod2,momSmBuff1,momSmBuff2)==0)
      return 0;
   if(ExponentialMAOnBuffer(rates_total,prev_calculated,smperiod1,smperiod2,absMomSmBuff1,absMomSmBuff2)==0)
      return 0;
   for(int i=limit; i>=0 && !IsStopped(); i--)
      indBuff[i]=(absMomSmBuff2[i]!=0 ? 100.0*momSmBuff2[i]/absMomSmBuff2[i] : 0);
   return(rates_total);
  }

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

simpleTSI inputs win

Итак, у нас есть два входных параметра, которые может определить пользователь, и значения по умолчанию: 25 для периода сглаживания 1 и 13 для периода сглаживания 2. Но тем не менее, как мы уже упоминали, пользователь может редактировать их в соответствии со своими предпочтениями.

 simpleTSI colors win

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

 simpleTSI attached

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


Пользовательский советник TSI

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

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

  • Создание целочисленной переменной (TSI).
  • Определение TSI с использованием функции iCustom для возврата дескриптора индикатора и его параметров:
    • symbol — имя символа; у нас это _Symbol, то есть рассчитываем индикатор по символу текущего графика.
    • period — таймфрейм для расчета; значение _period означает, что индикатор будет рассчитываться на текущем таймфрейме.
    • name — путь к пользовательскому индикатору.
  • Вывод текста "TSI System Removed" (TSI System удален) в OnDeinit(const int reason) после удаления советника.
  • Создадим массив tsiVal[]
  • Получение данных буфера индикатора TSI с помощью функции CopyBuffer с вариантом вызова по первой позиции и количеству необходимых элементов. Параметры такие:
    • indicator_handle — возвращенный хендл индикатора, который мы будем использовать (TSI).
    • buffer_num — номер индикаторного буфера, установим (0).
    • start_pos — начальная позиция для копирования, укажем (0).
    • count — количество данных для копирования, укажем (1).
    • buffer[]: копируемый массив, укажем (tsiVal).
  • Используя функцию Comment, чтобы показать текущее значение TSI, преобразованное в строку, с помощью функции (DoubleToString) с параметрами value для указания текущего значения TSI и цифр для указания количества цифр, мы будем использовать (_Digits) для текущего значения.

Полный код этой системы будет таким:

//+------------------------------------------------------------------+
//|                                           customSimpleTSI-EA.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
int TSI;
int OnInit()
  {
   TSI=iCustom(_Symbol,_Period,"My Files\\TSI\\simpleTSI");
   return(INIT_SUCCEEDED);
  }
void OnDeinit(const int reason)
  {
   Print("TSI System Removed");
  }
void OnTick()
  {
   double tsiVal[];
   CopyBuffer(TSI,0,0,1,tsiVal);
   Comment("TSI Value ",DoubleToString(tsiVal[0],_Digits));
  }

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

 Сигнал советника iCustom TSI

Как мы видим, в левом верхнем углу графика указано текущее значение TSI. Если мы хотим убедиться, что сигнал такой же, как наш на основе индикатора, мы можем прикрепить советник и одновременно указать индикатор в качестве значений. Убедимся, что всё работает:

Запущен советник iCustom TSI - сигнал тот же

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


Советник TSI System

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

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

В дополнение к нашему пользовательскому индикатору TSI мы будем использовать две простые скользящие средние (MA): одну быструю с периодом 10, а другую медленную с периодом 20. Если предыдущее значение быстрой MA меньше предыдущей медленной MA и в то же время текущая быстрая MA больше текущей медленной MA, это означает, что мы имеем бычье пересечение MA. Тогда мы проверим, больше ли текущее значение TSI, чем ноль. Нам нужно получить сигнал на покупку в качестве комментария на графике. Если предыдущее значение быстрой MA больше предыдущей медленной MA и в то же время текущая быстрая MA меньше текущей медленной MA, это означает, что мы имеем медвежье пересечение MA. Тогда мы проверим, меньше ли текущее значение TSI, чем ноль. Нам нужно получить сигнал на продажу в качестве комментария на графике.

Схематично:

Если fastMA[1]<slowMA[1] && fastMA[0]>slowMA[0] && tsiVal[0]>0 ==> Сигнал на покупку
Если fastMA[1]>slowMA[1] && fastMA[0]<slowMA[0] && tsiVal[0]<0 ==> Сигнал на продажу

Полный код для создания такой торговой системы выглядит так:

//+------------------------------------------------------------------+
//|                                                TSI System EA.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
input ENUM_MA_METHOD inpMAType = MODE_SMA; //Moving Average Type
input ENUM_APPLIED_PRICE inpPriceType = PRICE_CLOSE; //Price type
input int inpFastMAPeriod = 10; // Fast moving average period
input int inpSlowMAPeriod = 20; //Slow moving average period
int tsi;
double fastMAarray[], slowMAarray[];
int OnInit()
  {
   tsi=iCustom(_Symbol,_Period,"My Files\\TSI\\simpleTSI");
   return(INIT_SUCCEEDED);
  }
void OnDeinit(const int reason)
  {
   Print("TSI System Removed");
  }
void OnTick()
  {
   double tsiVal[];
   CopyBuffer(tsi,0,0,1,tsiVal);
   int fastMA =iMA(_Symbol,_Period,inpFastMAPeriod,0,inpMAType,inpPriceType);
   int slowMA =iMA(_Symbol,_Period,inpSlowMAPeriod,0,inpMAType,inpPriceType);
   ArraySetAsSeries(fastMAarray,true);
   ArraySetAsSeries(slowMAarray,true);
   CopyBuffer(fastMA,0,0,3,fastMAarray);
   CopyBuffer(slowMA,0,0,3,slowMAarray);
   if(fastMAarray[1]<slowMAarray[1]&&fastMAarray[0]>slowMAarray[0])
     {
      if(tsiVal[0]>0)
        {

         Comment("Buy Signal",
                 "\nTSI Value ",DoubleToString(tsiVal[0],_Digits),
                 "\nfastMA ",DoubleToString(fastMAarray[0],_Digits),
                 "\nslowMA ",DoubleToString(slowMAarray[0],_Digits));
        }
     }
   if(fastMAarray[1]>slowMAarray[1]&&fastMAarray[0]<slowMAarray[0]&&tsiVal[0]<0)
     {
      if(tsiVal[0]<0)
        {
         Comment("Sell Signal",
                 "\nTSI Value ",DoubleToString(tsiVal[0],_Digits),
                 "\nfastMA ",DoubleToString(fastMAarray[0],_Digits),
                 "\nslowMA ",DoubleToString(slowMAarray[0],_Digits));
        }
     }
  }

Какие отличия появились в этом коде:

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

input ENUM_MA_METHOD inpMAType = MODE_SMA; //Moving Average Type
input ENUM_APPLIED_PRICE inpPriceType = PRICE_CLOSE; //Price type
input int inpFastMAPeriod = 10; // Fast moving average period
input int inpSlowMAPeriod = 20; //Slow moving average period

Создание двух массивов для массива быстрой MA и медленной MA.

double fastMAarray[], slowMAarray[];

Определение двух скользящих средних с использованием предопределенной функции iMA для возврата дескриптора скользящего среднего и его параметров:

  • symbol — символ для расчетов; _Symbol означает символ текущего графика.
  • period — период для расчетов, _Period означает текущий таймфрейм.
  • ma_period — входные параметры для быстрых и медленных скользящих средних.
  • ma_shift — укажем (0), поскольку сдвиг не требуется.
  • ma_method — тип MA.
  • applied _price — тип цены.
   int fastMA =iMA(_Symbol,_Period,inpFastMAPeriod,0,inpMAType,inpPriceType);
   int slowMA =iMA(_Symbol,_Period,inpSlowMAPeriod,0,inpMAType,inpPriceType);

Установка флага AS_SERIES с помощью функции ArraySetAsSeries для медленных и быстрых MA

   ArraySetAsSeries(fastMAarray,true);
   ArraySetAsSeries(slowMAarray,true);

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

   CopyBuffer(fastMA,0,0,3,fastMAarray);
   CopyBuffer(slowMA,0,0,3,slowMAarray);

Определение условий стратегии,

В случае сигнала на покупку:

Если предыдущая быстрая MA (fastMA) меньше предыдущей медленной MA (slowMA), а текущая быстрая MA больше текущей медленной MA и при этом текущий tsiVal больше нуля, то нам нужно, чтобы советник возвращал сигнал на покупку в виде комментария на графике в следующем порядке:

  • Сигнал на покупку
  • Значение TSI
  • Значение быстрой MA
  • Значение медленной MA
   if(fastMAarray[1]<slowMAarray[1]&&fastMAarray[0]>slowMAarray[0])
     {
      if(tsiVal[0]>0)
        {

         Comment("Buy Signal",
                 "\nTSI Value ",DoubleToString(tsiVal[0],_Digits),
                 "\nfastMA ",DoubleToString(fastMAarray[0],_Digits),
                 "\nslowMA ",DoubleToString(slowMAarray[0],_Digits));
        }
     }

В случае сигнала на продажу:

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

  • Сигнал на продажу
  • Значение TSI
  • Значение быстрой MA
  • Значение медленной MA
   if(fastMAarray[1]>slowMAarray[1]&&fastMAarray[0]<slowMAarray[0]&&tsiVal[0]<0)
     {
      if(tsiVal[0]<0)
        {
         Comment("Sell Signal",
                 "\nTSI Value ",DoubleToString(tsiVal[0],_Digits),
                 "\nfastMA ",DoubleToString(fastMAarray[0],_Digits),
                 "\nslowMA ",DoubleToString(slowMAarray[0],_Digits));
        }
     }

После компиляции этого кода без ошибок и перетаскивания его на график, откроется окно входных данных:

Входные параметры советника TSI System

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

В случае сигнала на покупку

 Советник TSI System - сигнал на покупку

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

  • Сигнал на покупку
  • Значение TSI
  • Значение быстрой MA
  • Значение медленной MA

В случае сигнала на продажу:

 Советник TSI System - сигнал на продажу

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

  • Сигнал на продажу
  • Значение TSI
  • Значение быстрой MA
  • Значение медленной MA

Заключение

В этой статье мы узнали, как создать свой собственный технический индикатор True Strength Index с учетом конкретных настроек и предпочтений. Мы увидели, какую информацию и идеи предоставляет этот индикатор, что может быть очень полезно в торговле. Мы также узнали, как можно использовать этот настраиваемый индикатор в простой торговой системе для генерации текущего значения индикатора TSI в качестве комментария к графику. Мы также увидели, как использовать индикатор в автоматической торговой системе, создав советник, который использует данные TSI в сочетании с другим техническим инструментом, которым в нашем случае является скользящее среднее. Эта комбинация пользовательского TSI и двух скользящих средних генерирует сигналы на покупку и продажу на основе конкретной стратегии, которую мы подробно рассмотрели в разделе о советнике TSI System.

Я надеюсь, что эта статья будет полезна для вашего обучения трейдингу и программированию. Если вы хотите прочитать другие статьи об индикаторах и узнать, как создавать торговые системы на основе самых популярных технических индикаторов, прочтите мои предыдущие статьи, в которых я рассказываю о таких популярных индикаторах, как скользящее среднее, полосы Боллинджера, RSI, MACD, Стохастик, Parabolic SAR, ATR и другие.

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

Прикрепленные файлы |
simpleTSI.mq5 (7.46 KB)
iCustomTSI_ea.mq5 (0.81 KB)
TSI_System_EA.mq5 (2.09 KB)
Парный трейдинг Парный трейдинг
В этой статье мы рассмотрим парный трейдинг: какие принципы лежат в его основе, есть ли перспективы его применения на практике. Заодно, попробуем создать стратегию парного трейдинга.
Нейросети — это просто (Часть 57): Стохастический маргинальный актор-критик (SMAC) Нейросети — это просто (Часть 57): Стохастический маргинальный актор-критик (SMAC)
Предлагаем познакомиться с довольно новым алгоритмом Stochastic Marginal Actor-Critic (SMAC), который позволяет строить политики латентных переменных в рамках максимизации энтропии.
Понимание и эффективное использование тестера стратегий MQL5 Понимание и эффективное использование тестера стратегий MQL5
MQL5-разработчикам крайне необходимо освоить важные и ценные инструменты. Одним из таких инструментов является тестер стратегий. Статья представляет собой практическое руководство по использованию тестера стратегий MQL5.
Теория категорий в MQL5 (Часть 12): Порядок Теория категорий в MQL5 (Часть 12): Порядок
Статья является частью серии о реализации графов средствами теории категорий в MQL5 и посвящена отношению порядка (Order Theory). Мы рассмотрим два основных типа упорядочения и исследуем, как концепции отношения порядка могут поддерживать моноидные множества при принятии торговых решений.