English 中文 Español Deutsch 日本語 Português
Звуковые сигналы в индикаторах

Звуковые сигналы в индикаторах

MetaTrader 4Трейдинг | 26 декабря 2006, 15:41
28 644 64
Andrey Khatimlianskii
Andrey Khatimlianskii


Вступление


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

Как и несколько лет назад, многие трейдеры для анализа пользуются Техническими индикаторами - одним или несколькими сразу. А некоторые стратегии учитывают значения индикаторов одновременно на нескольких периодах.

Как не пропустить важный сигнал? Есть несколько вариантов:
  • Написать эксперта, который будет анализировать рынок и сообщать о важных событиях;
  • Сидеть возле монитора и, переключаясь между десятками графиков, пытаться сопоставить полученную информацию;
  • Добавить во все используемые индикаторы систему оповещения о торговых сигналах.
Первый вариант по моему мнению наиболее правильный, но требует либо навыков программиста либо денег на реализацию. Второй - очень трудоемкий, утомительный и нерациональный. А третий вариант - нечто среднее между первыми двумя. Для его реализации необходимо намного меньше времени и умений, но он значительно облегчит жизнь (работу) трейдеру, торгующему вручную.

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

Виды сигналов


Способов интерпретации индикаторов существует очень много. Даже стандартные индикаторы терминала MetaTrader 4 можно понимать по разному. О всевозможных пользовательских индикаторах я вообще молчу...

Кто-то покупает, когда главная линия MACD пересекает сигнальную, кто-то ждет пересечения с нулевой линией, а кто-то открывает длинную позицию, когда MACD меньше 0 и начинает движение вверх. Предусмотреть все возможные варианты интерпретации мне не представляется возможным, поэтому я вам расскажу принцип добавления сигнального блока, а вы, отталкиваясь от него, сможете добавить любой тип сигнала в большинство индикаторов.

Итак, какие виды сигналов у нас есть:
  • Пересечение двух линий индикатора (пример приведен выше - главная линия MACD и сигнальная линия);
  • Пересечение линией индикатора определенного уровня (главная линия MACD и нулевая линия, Stoсhastic и уровни 70 и 30, CCI и уровни -100 и 100);
  • Изменение направления движения (AC и AO, обычный MA);
  • Изменение расположения по отношению к цене (Parabolic SAR);
  • Появление стрелочки над или под ценой (Fractals).
Наверное, существуют ещё какие-то способы интерпретации, я просто о них забыл или не знал вообще, поэтому пока остановимся на этих пяти.

Способы оповещения


MetaTrader 4 и MQL 4 позволяют реализовать несколько способов как визуального, так и звукового оповещения:
  • Обычное сообщение на экран (функция Comment);
  • Текст в журнале (функция Print);
  • Окно с сообщением и звуковой сигнал (функция Alert);
  • Отдельный звуковой сигнал с выбором воспроизводимого файла (функция PlaySound).
Кроме того, есть функция отправки файла на FTP-сервер (функция SendFTP()), вывода диалогового окна с сообщением (MessageBox()) и отправки почтового сообщения (SendMail()). Функция SendFTP() вряд ли будет востребована обычным пользователем, MessageBox() не подходит для использования в индикаторе, так как останавливает его работу до закрытия окна сообщения, а SendMail(), хоть и удобна для отправки SMS-сообщений, достаточно "опасна" в использовании - оставив несколько индикаторов на графике, вы обеспечите себе нескончаемый и нерегулируемый поток сообщений. Функцию использовать можно, но лучше из советника, например, отправлять сообщение при появлении сигнала на нескольких индикаторах одновременно, уделив ей достаточно внимания.

В этой статье мы рассмотрим только способы звукового и визуального оповещения терминала MetaTrader 4.

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

Но, как известно, на вкус и цвет товарищей нет. Поэтому я сделаю заготовку для всех упомянутых способов (кроме SendFTP, MessageBox и SendMail), а вы выберете удобный для себя.

Фильтр на частоту сигналов


Если вы уже когда-нибудь пользовались сигналами в индикаторах, то наверняка сталкивались с их чрезмерной частотой, особенно, если речь идет о мелких таймфреймах. Решается эта проблема несколькими способами:
  • Сигналы определять на основании сформировавшихся баров. Это наиболее правильное решение;
  • Чередовать сигналы - после покупки только продажа, и наоборот (тоже очень логичный ход, его можно использовать одновременно с другими);
  • Делать паузу между сигналами (не очень хорошая идея);
  • Давать один сигнал на бар (тоже достаточно искусственное ограничение).
Использовать ли сигнал с нулевого, несформировавшегося, бара для торговли - личное дело каждого. Я, например, считаю что это неправильно. Но есть индикаторы требующие моментальной реакции - для них один бар это слишком много. Поэтому дадим пользователю выбор. Несколько сигналов на покупку подряд вряд ли имеют смысл, поэтому все сигналы будем чередовать. А искусственные паузы вводить, пожалуй, не будем. Если они действительно понадобятся, об этом напишут в комментариях к статье.

Итак, приступим к реализации.

Сигнал первый - пересечение двух индикаторных линий


Начнем с приводимого в примерах MACD.

Главная наша задача - определить в каких массивах хранятся линии индикатора. Для этого посмотрим в код:
//---- indicator settings
#property  indicator_separate_window
#property  indicator_buffers 2
#property  indicator_color1  Silver
#property  indicator_color2  Red
#property  indicator_width1  2
//---- indicator parameters
extern int FastEMA = 12;
extern int SlowEMA = 26;
extern int SignalSMA = 9;
//---- indicator buffers
double MacdBuffer[];
double SignalBuffer[];

Обратите внимание на комментарий "indicator buffers" - это именно то, что мы искали. Такие массивы чаще всего имеют интуитивно понятное имя (MacdBuffer - буфер значения главной линии MACD, SignalBuffer - буфер сигнальной линии) и всегда располагаются вне функций init, deinit и start.

Если массивов много и сложно понять какой из них необходим, посмотрите в функцию init - все массивы, отображенные на графике, "привязываются" к определенному номеру с помощью функции SetIndexBuffer:
int init()
  {
//---- drawing settings
   SetIndexStyle(0, DRAW_HISTOGRAM);
   SetIndexStyle(1, DRAW_LINE);
   SetIndexDrawBegin(1, SignalSMA);
   IndicatorDigits(Digits + 1);
//---- indicator buffers mapping
   SetIndexBuffer(0, MacdBuffer);
   SetIndexBuffer(1, SignalBuffer);
//---- name for DataWindow and indicator subwindow label
   IndicatorShortName("sMACD(" + FastEMA + "," + SlowEMA + "," + SignalSMA + ")");
   SetIndexLabel(0, "sMACD");
   SetIndexLabel(1, "sSignal");
//---- initialization done
   return(0);
  }
И именно в таком порядке (от 0 до 7) значения линий индикатора отображаются в окне DataWindow. Имена, которые вы увидите там же, назначаются функцией SetIndexLabel - это третий способ идентификации.

Теперь, когда мы знаем, где хранятся необходимые данные, можем переходить к реализации сигнального блока. Для этого перемещаемся в самый конец функции start - выше последнего оператора return:

   for(i = 0; i < limit; i++)
       SignalBuffer[i] = iMAOnArray(MacdBuffer, Bars,S ignalSMA, 0, MODE_SMA, i);
//---- done
 
// а сюда мы добавим наш код
 
   return(0);
  }
//+------------------------------------------------------------------+
Ни в коем случае нельзя добавлять сигнальный блок в цикл расчета индикатора - это замедлит его работу и не принесет никакой пользы.

Итак, начинаем сочинять:
    //---- Статические переменные, в которых хранятся
    //---- время последнего бара и направление последнего сигнала
    static int PrevSignal = 0, PrevTime = 0;
 
    //---- Если баром для анализа выбран не 0-й, нам нет смысла проверять сигнал
    //---- несколько раз. Если не начался новый бар, выходим.
    if(SIGNAL_BAR > 0 && Time[0] <= PrevTime ) 
        return(0);
    //---- Отмечаем, что этот бар проверен
    PrevTime = Time[0];
Каждый раз, когда будет выполняться функция start, будет выполняться наш код. Обычные переменные обнуляются после каждого выполнения функции. Поэтому для хранения последнего сигнала и номера просчитанного бара мы объявили две статические переменные.
Дальше находится простая проверка, начался ли новый бар (работает только, если SIGNAL_BAR больше 0).

Кстати, саму переменную SIGNAL_BAR мы объявили намного раньше, ещё до функции init:
double     SignalBuffer[];
 
//---- Номер бара, по которому будет искаться сигнал
#define SIGNAL_BAR 1
 
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
Обратите внимание на директиву #define - компилятор просто заменит во всем коде переменную SIGNAL_BAR указанным значением (1).

Теперь, собственно, код сигнала:
    //---- Если предыдущий сигнал был СЕЛЛ или это первый запуск (PrevSignal=0)
    if(PrevSignal <= 0)
      {
        //---- Проверяем, не пересеклись ли линии на прошлом баре:
        if(MacdBuffer[SIGNAL_BAR] - SignalBuffer[SIGNAL_BAR] > 0 && 
           SignalBuffer[SIGNAL_BAR+1] - MacdBuffer[SIGNAL_BAR+1] >= 0)
          {
            //---- Если пересеклись, отмечаем что последний сигнал - бай
            PrevSignal = 1;
            //---- и выводим информацию:
            Alert("sMACD (", Symbol(), ", ", Period(), ")  -  BUY!!!");
//            Print("sMACD (", Symbol(), ", ", Period(), ")  -  BUY!!!");
//            Comment("sMACD (", Symbol(), ", ", Period(), ")  -  BUY!!!");
//            PlaySound("Alert.wav");
          }
      }

Тут тоже все просто. Если предыдущий сигнал был на продажу, проверяем пересечение линий:
если  значение главной линии MACD на баре №1 больше, чем значение сигнальной линии на баре №1
    И
значение сигнальной линии на баре №2 больше, чем значение линии MACD на баре №2
    значит
линии пересеклись.

Дальше отмечаем, что последний сигнал был на покупку, и выводим сообщение. Обратите внимание на три закомментированные строки - это ещё три варианта оповещения. Вы можете разкомментировать или удалить любую из них или все сразу. По умолчанию я оставил только Alert, как самый удобный.
А в функции PlaySound можно указать, какой аудио файл проигрывать. Файл должен находиться в директории MetaTrader 4\sounds\ и иметь расширение wav. Например, сделать свой звук на сигнал бай и свой - на селл или разные звуки разным индикаторам.

Сигнал на продажу полностью аналогичен:
    //---- Полностью аналогично для сигнала СЕЛЛ
    if(PrevSignal >= 0)
      {
        if(SignalBuffer[SIGNAL_BAR] - MacdBuffer[SIGNAL_BAR] > 0 && 
           MacdBuffer[SIGNAL_BAR+1] - SignalBuffer[SIGNAL_BAR+1] >= 0)
          {
            PrevSignal = -1;
            Alert("sMACD (", Symbol(), ", ", Period(), ")  -  SELL!!!");
//            Print("sMACD (", Symbol(), ", ", Period(), ")  -  SELL!!!");
//            Comment("sMACD (", Symbol(), ", ", Period(), ")  -  SELL!!!");
//            PlaySound("Alert.wav");
          }
      }

Остальные сигналы


Теперь, когда мы освоились в коде индикатора, нам будет намного проще написать другие блоки оповещения. Меняться будет только "формула", остальной код будем просто копировать.

Сигнал на пересечение определенного уровня очень похож на пересечение линий. Я его добавил в Stochastic, но вы можете провести аналогию для любого другого индикатора:
    if(PrevSignal <= 0)
      {
        if(MainBuffer[SIGNAL_BAR] - 30.0 > 0 && 
           30.0 - MainBuffer[SIGNAL_BAR+1] >= 0)
          {
            PrevSignal = 1;
            Alert("sStochastic (", Symbol(), ", ", Period(), ")  -  BUY!!!");
          }
      }
    if(PrevSignal >= 0)
      {
        if(70.0 - MainBuffer[SIGNAL_BAR] > 0 && 
           MainBuffer[SIGNAL_BAR+1] - 70.0 >= 0)
          {
            PrevSignal = -1;
            Alert("sStochastic (", Symbol(), ", ", Period(), ")  -  SELL!!!");
          }
      }
Как видите, при пересечении линией %K (MainBuffer) уровня 30 снизу вверх индикатор скажет "Buy", а при пересечении уровня 70 сверху вниз - "Sell".

Третий вид сигнала - изменение направления движения. Его мы рассмотрим на примере индикатора AC. Обратите внимание, в этом индикаторе используется пять буферов:
//---- indicator buffers
double     ExtBuffer0[];
double     ExtBuffer1[];
double     ExtBuffer2[];
double     ExtBuffer3[];
double     ExtBuffer4[];

ExtBuffer3 и ExtBuffer4 используются для промежуточных расчетов, ExtBuffer0 всегда хранит знчение индикатора, а ExtBuffer2 и ExtBuffer3 "разукрашивают" столбики в 2 цвета. Поскольку нам необходимо только значение индикатора, будем использовать ExtBuffer0:
    if(PrevSignal <= 0)
      {
        if(ExtBuffer0[SIGNAL_BAR] - ExtBuffer0[SIGNAL_BAR+1] > 0 &&
           ExtBuffer0[SIGNAL_BAR+2] - ExtBuffer0[SIGNAL_BAR+1] > 0)
          {
            PrevSignal = 1;
            Alert("sAC (", Symbol(), ", ", Period(), ")  -  BUY!!!");
          }
      }
    if(PrevSignal >= 0)
      {
        if(ExtBuffer0[SIGNAL_BAR+1] - ExtBuffer0[SIGNAL_BAR] > 0 &&
           ExtBuffer0[SIGNAL_BAR+1] - ExtBuffer0[SIGNAL_BAR+2] > 0)
          {
            PrevSignal = -1;
            Alert("sAC (", Symbol(), ", ", Period(), ")  -  SELL!!!");
          }
      }

Если значение индикатора уменьшалось, а потом начало увеличиваться, даем сигнал на покупку, если наоборот - увеличивалось и начало уменьшаться - на продажу.

Четвертый вид сигнала - изменение расположения по отношению к цене - достаточно редкий.
Но все равно его можно встретить, например, в Parabolic-е. На его примере мы и напишем "формулу":
    if(PrevSignal <= 0)
      {
        if(Close[SIGNAL_BAR] - SarBuffer[SIGNAL_BAR] > 0)
          {
            PrevSignal = 1;
            Alert("sParabolic Sub (", Symbol(), ", ", Period(), ")  -  BUY!!!");
          }
      }
    if(PrevSignal >= 0)
      {
        if(SarBuffer[SIGNAL_BAR] - Close[SIGNAL_BAR] > 0)
          {
            PrevSignal = -1;
            Alert("sParabolic Sub(", Symbol(), ", ", Period(), ")  -  SELL!!!");
          }
      }

Тут вообще все просто - сравниваем значение индикатора с ценой закрытия бара. Заметьте, если установить SIGNAL_BAR равным 0, каждое "прикосновение" цены к параболику будет сопровождаться сигналом.

И последний сигнал - появление стрелочки на графике. В стандартных индикаторах он встречается достаточно редко, зато очень распространен в пользовательских "определителях разворотов". Я рассмотрю этот вид сигналов на примере индикатора Fractals (исходный код на MQL 4 находится в Code Base: Fractals).

Общим для всех подобных индикаторов является то, что в тех местах, где они рисуются на графиках, они не равны 0 (или EMPTY_VALUE). На всех остальных барах их буферы пустые. То есть для определения сигнала достаточно сравнить значение буфера с 0:
    if(PrevSignal <= 0 )
      {
        if(ExtDownFractalsBuffer[SIGNAL_BAR] > 0)
          {
            PrevSignal = 1;
            Alert("sFractals (", Symbol(), ", ", Period(), ")  -  BUY!!!");
          }
      }
    if(PrevSignal >= 0)
      {
        if(ExtUpFractalsBuffer[SIGNAL_BAR] > 0)
          {
            PrevSignal = -1;
            Alert("sFractals (", Symbol(), ", ", Period(), ")  -  SELL!!!");
          }
      }

Но если вы присоедините индикатор с таким кодом на график, вы никогда не дождетесь сигнала. У фракталов есть одна особенность - они используют 2 будущих бара для анализа, поэтому стрелочки появляются только на втором по номеру (или третьем по счету - 0-й, 1-й, 2-й) баре. Поэтому для того, чтоб сигналы заработали, надо установить SIGNAL_BAR равным 2:
//---- Номер бара, по которому будет искаться сигнал
#define SIGNAL_BAR 2

Всё, теперь сигналы будут работать!

Заключение


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

Среди видов сигналов были выделены и реализованы:
  • Пересечение двух линий индикатора;
  • Пересечение линией индикатора определенного уровня;
  • Изменение направления движения;
  • Изменение расположения по отношению к цене;
  • Появление стрелочки над или под ценой.
Для оповещения были выбраны функции:
  • Comment() - для обычного сообщения на экран;
  • Print() - для отображения сообщения в журнале;
  • Alert() - для отображения сообщения в специальном окне и звукового сигнала;
  • и PlaySound() - для воспроизведения любого звукового файла.
Для уменьшения частоты сигналов:
  • При определении сигнала использовались сформировавшиеся бары;
  • Все сигналы чередовались - после покупки только продажа, и наоборот.
На примере пяти индикаторов, соответствующих пяти видам сигналов, были рассмотрены их сигнальные блоки. Полученные индикаторы можно скачать - ссылки в конце статьи.

Я надеюсь, вы убедились, что ничего сложного в добавлении сигнального блока в индикаторы нет - это по силам каждому. Может быть, теперь на форумах будет меньше подобных просьб и мы сможем развиваться дальше.
Прикрепленные файлы |
sAccelerator.mq4 (4.38 KB)
sFractals.mq4 (7.4 KB)
sMACD.mq4 (4.25 KB)
sParabolic_Sub.mq4 (8.46 KB)
sStochastic.mq4 (5.22 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (64)
zxzxz
zxzxz | 11 сент. 2019 в 18:59
Andrey KhatimlianskiiСпасибо

Спасибо,помощь больше не требуется! Я благодаря Вам разобрался, все работает!...еще раз спасибо.

Andrey Khatimlianskii
Andrey Khatimlianskii | 11 сент. 2019 в 20:36
zxzxz:

Спасибо,помощь больше не требуется! Я благодаря Вам разобрался, все работает!...еще раз спасибо.

Да, все правильно, в моем примере как раз ваш сигнал Бай.

Спасибо за отзыв!

zxzxz
zxzxz | 18 сент. 2019 в 15:10
Andrey Khatimlianskii:

А,зачем необходимо ставить значение (+1) ?

//---- Гистограмма пересекла сигнальную линию вверх, находясь выше 0
        if(MacdBuffer[SIGNAL_BAR] > SignalBuffer[SIGNAL_BAR] && 
           MacdBuffer[SIGNAL_BAR+1] <= SignalBuffer[SIGNAL_BAR+1] &&
           MacdBuffer[SIGNAL_BAR+1] >= 0.0)  <---------------------------------ВОТ в ЭТОЙ ФУНКЦИИ!!!???
          {
            //---- Если пересеклись, отмечаем что последний сигнал - бай
            PrevSignal = 1;
            //---- и выводим информацию:
            Alert("sMACD (", Symbol(), ", ", Period(), ")  -  BUY!!!");
Andrey Khatimlianskii
Andrey Khatimlianskii | 19 сент. 2019 в 12:49
zxzxz:

А,зачем необходимо ставить значение (+1) ?

Для анализа предыдущего бара.

Mazut-export
Mazut-export | 10 нояб. 2022 в 22:55
Treyder007 #:

добрый день ребята, у меня вопрос: можно ли поставить алерт так чтобы по пересечению уровни поддержки и сопротивлении оповещал текстовым образом по какой валютной паре это происходит, а то у меня price alert индикатор оповещает правильном образом но в тексте написано только price above the alert level и все... не понятно по какой паре пришел алерт и начинаешь искать среди 15 валютных пар и упускаешь хороши момент

Привет! А я на разные валютные пары включил разную, но только соответствующую мелодию (Например на GBP у меня Лепс поёт-Я уеду жить в Лондон))))) Да, кто-то покрутит пальцем у виска, зато мне ясно какая валюта созрела.

Костя. mazut-export@yandex.ru 

Работа MetaTrader 4 под защитой антивирусов и файрволов Работа MetaTrader 4 под защитой антивирусов и файрволов
Большинство пользователей используют для защиты своих компьютеров специализированные программы. К сожалению, эти программы не только защищают компьютеры от вторжений, вирусов и троянов, но и потребляют достаточное количество ресурсов. В первую очередь это касается сетевого трафика, который на 100% контролируется разнообразными интеллектуальными файрволами и антивирусами. Поводом для написания этой статьи послужили обращения трейдеров, которые жаловались на замедление работы терминала МетаТрейдер при работе с Outpost Firewall. Мы решили провести собственные исследования на примере Антивируса Касперского 6.0 и файрвола Outpost Pro 4.0
Как найти прибыльную торговую стратегию Как найти прибыльную торговую стратегию
В статье дан ответ на вопрос: "Можно ли, используя нейронные сети, на исторических данных сформулировать торговую стратегию с помощью компьютера?".
Ошибки начинающего трейдера при работе с клиентским терминалом MetaTrader 4 Ошибки начинающего трейдера при работе с клиентским терминалом MetaTrader 4
Все люди ошибаются - кто-то чаще, кто-то реже, кто-то по незнанию, кто-то по невнимательности. Вы спрашиваете - мы отвечаем: время в терминале, результаты тестирования, Print в журнал, символы, история для тестера, импорт истории, плечо, трафик, всплывающие подсказки, масштаб, неверный счет, Invalid account, пустые новости, Price changed, Not Enough Money, Market Is Closed.
Что такое мартингал? Что такое мартингал?
Краткое описание различного рода иллюзий, возникающих при игре на мартингале, применении стратегии мартингала или при злоупотреблении спайкингом и родственными приемами.