![Рецепты MQL5 - Озвучиваем торговые события в MetaTrader 5](https://c.mql5.com/i/articles/overlay.png)
Рецепты MQL5 - Озвучиваем торговые события в MetaTrader 5
Введение
В этой статье мы рассмотрим такие вопросы, как включение в файл эксперта звуковых файлов и, соответственно, озвучивание торговых событий. Включение файлов означает, что звуковые файлы будут находиться внутри эксперта, и если передать скомпилированную версию эксперта (*.ex5) другому пользователю, то не нужно будет передавать ему звуковые файлы и объяснять при этом, в какую папку их положить.
Процесс разработки
Для теста возьмем эксперта из предыдущей статьи Рецепты MQL5 - Сохраняем результаты оптимизации торгового эксперта по указанным критериям. Я убрал из него все, что не относится к текущей теме, чтобы было проще.
Чтобы озвучить торговое событие средствами MQL5 можно воспользоваться функциями Alert() и PlaySound(). Если использовать функцию Alert(), то будет воспроизводиться всегда один и тот же звук, при этом будет открываться окно с сообщением. Как это выглядит можно посмотреть в статье Рецепты MQL5 - Вывод информации на печать в разных режимах.
Звук для алерта можно установить в настройках терминала: Сервис -> Настройки или Ctrl+O. Далее в разделе События нужно установить флажок Разрешить звуковые оповещения о событиях и в выпадающем списке алертов выбрать подходящий звуковой файл.
Рис. 1 - Вкладка "События" в настройках терминала
Но для каждого события, которое воспроизводит пользовательская программа, есть возможность установить уникальный звук, и для этого нам понадобится функция PlaySound().
Прежде чем встраивать звуковые оповещения в торгового эксперта, сделаем эксперта для тестов. Сделаем так, чтобы при загрузке эксперта на графике открывалась звуковая панель. Звуковую панель соберем из графических объектов типа кнопка (OBJ_BUTTON). Каждой кнопке будет присвоен уникальный звук, который будет воспроизводиться при нажатии.
В интернете я нашел 25 разных звуковых файлов в формате *.wav (скачать их можно в конце статьи). Их нужно расположить в директории MetaTrader 5\MQL5\Files\Sounds. Для тренировки навыков работы со звуковыми файлами с помощью Мастера MQL5 создадим нового эксперта. В самом начале обозначим размер массива по количеству кнопок на звуковой панели (всего их будет 26).
//--- Размер массива #define ARRAY_SIZE 26
Далее нужно указать директории и имена файлов, которые должны стать ресурсами эксперта. Это можно сделать с помощью директивы #resource. После директивы в двойных кавычках нужно указывать путь к файлу:
//--- Звуковые файлы #resource "\\Files\\Sounds\\alert.wav" #resource "\\Files\\Sounds\\AHOOGA.wav" #resource "\\Files\\Sounds\\APPLAUSE.wav" #resource "\\Files\\Sounds\\BONK.wav" #resource "\\Files\\Sounds\\CARBRAKE.wav" #resource "\\Files\\Sounds\\CASHREG.wav" #resource "\\Files\\Sounds\\CLAP.wav" #resource "\\Files\\Sounds\\CORKPOP.wav" #resource "\\Files\\Sounds\\DOG.wav" #resource "\\Files\\Sounds\\DRIVEBY.wav" #resource "\\Files\\Sounds\\DRUMROLL.wav" #resource "\\Files\\Sounds\\EXPLODE.wav" #resource "\\Files\\Sounds\\FINALBEL.wav" #resource "\\Files\\Sounds\\FROG.wav" #resource "\\Files\\Sounds\\GLASS.wav" #resource "\\Files\\Sounds\\GUNSHOT.wav" #resource "\\Files\\Sounds\\LASER.wav" #resource "\\Files\\Sounds\\LATNWHIS.wav" #resource "\\Files\\Sounds\\PIG.wav" #resource "\\Files\\Sounds\\RICOCHET.wav" #resource "\\Files\\Sounds\\RINGIN.wav" #resource "\\Files\\Sounds\\SIREN.wav" #resource "\\Files\\Sounds\\TRAIN.wav" #resource "\\Files\\Sounds\\UH_OH.wav" #resource "\\Files\\Sounds\\VERYGOOD.wav" #resource "\\Files\\Sounds\\WHOOSH.wav"
Теперь нужно создать три строковых массива, которые будут содержать пути к файлам ресурсов, имена графических объектов и отображаемый текст на графических объектах. Обратите внимание на два двоеточия в пути к файлам - специальный признак для обращения к ресурсу по имени.
//--- Путь к звуковым файлам string sound_paths[ARRAY_SIZE]= { "::Files\\Sounds\\alert.wav", "::Files\\Sounds\\AHOOGA.wav", "::Files\\Sounds\\APPLAUSE.wav", "::Files\\Sounds\\BONK.wav", "::Files\\Sounds\\CARBRAKE.wav", "::Files\\Sounds\\CASHREG.wav", "::Files\\Sounds\\CLAP.wav", "::Files\\Sounds\\CORKPOP.wav", "::Files\\Sounds\\DOG.wav", "::Files\\Sounds\\DRIVEBY.wav", "::Files\\Sounds\\DRUMROLL.wav", "::Files\\Sounds\\EXPLODE.wav", "::Files\\Sounds\\FINALBEL.wav", "::Files\\Sounds\\FROG.wav", "::Files\\Sounds\\GLASS.wav", "::Files\\Sounds\\GUNSHOT.wav", "::Files\\Sounds\\LASER.wav", "::Files\\Sounds\\LATNWHIS.wav", "::Files\\Sounds\\PIG.wav", "::Files\\Sounds\\RICOCHET.wav", "::Files\\Sounds\\RINGIN.wav", "::Files\\Sounds\\SIREN.wav", "::Files\\Sounds\\TRAIN.wav", "::Files\\Sounds\\UH_OH.wav", "::Files\\Sounds\\VERYGOOD.wav", "::Files\\Sounds\\WHOOSH.wav" }; //--- Имена графических объектов string sound_names[ARRAY_SIZE]= { "sound_button01","sound_button02", "sound_button03","sound_button04", "sound_button05","sound_button06", "sound_button07","sound_button08", "sound_button09","sound_button10", "sound_button11","sound_button12", "sound_button13","sound_button14", "sound_button15","sound_button16", "sound_button17","sound_button18", "sound_button19","sound_button20", "sound_button21","sound_button22", "sound_button23","sound_button24", "sound_button25","sound_button26" }; //--- Отображаемый текст на графических объектах string sound_texts[ARRAY_SIZE]= { "ALERT","AHOOGA","APPLAUSE","BONK","CARBRAKE","CASHREG", "CLAP","CORKPOP","DOG","DRIVEBY","DRUMROLL","EXPLODE","FINALBEL", "FROG","GLASS","GUNSHOT","LASER","LATNWHIS","PIG", "RICOCHET","RINGIN","SIREN","TRAIN","UH_OH","VERYGOOD","WHOOSH" };
Создадим функцию CreateButton(), которая будет создавать графический объект "Кнопка" на графике с указанными свойствами:
//+------------------------------------------------------------------+ //| Создание объекта Button | //+------------------------------------------------------------------+ void CreateButton(long chart_id, // id графика int sub_window, // номер окна string name, // имя объекта string text, // отображаемое имя ENUM_ANCHOR_POINT anchor, // точка привязки ENUM_BASE_CORNER corner, // угол графика string font_name, // шрифт int font_size, // размер шрифта color font_color, // цвет шрифта color background_color, // цвет фона color border_color, // цвет рамки int x_size, // ширина int y_size, // высота int x_distance, // координата по шкале X int y_distance, // координата по шкале Y long z_order) // приоритет { //--- Создание объекта if(ObjectCreate(chart_id,name,OBJ_BUTTON,sub_window,0,0)) { ObjectSetString(chart_id,name,OBJPROP_TEXT,text); // установка имени ObjectSetString(chart_id,name,OBJPROP_FONT,font_name); // установка шрифта ObjectSetInteger(chart_id,name,OBJPROP_COLOR,font_color); // установка цвета шрифта ObjectSetInteger(chart_id,name,OBJPROP_BGCOLOR,background_color); // установка цвета фона ObjectSetInteger(chart_id,name,OBJPROP_BORDER_COLOR,border_color); // установка цвета рамки ObjectSetInteger(chart_id,name,OBJPROP_ANCHOR,anchor); // установка точки привязки ObjectSetInteger(chart_id,name,OBJPROP_CORNER,corner); // установка угла привязки ObjectSetInteger(chart_id,name,OBJPROP_FONTSIZE,font_size); // установка размера шрифта ObjectSetInteger(chart_id,name,OBJPROP_XSIZE,x_size); // установка ширины X ObjectSetInteger(chart_id,name,OBJPROP_YSIZE,y_size); // установка высоты Y ObjectSetInteger(chart_id,name,OBJPROP_XDISTANCE,x_distance); // установка координаты X ObjectSetInteger(chart_id,name,OBJPROP_YDISTANCE,y_distance); // установка координаты Y ObjectSetInteger(chart_id,name,OBJPROP_SELECTABLE,false); // нельзя выделить объект, если FALSE ObjectSetInteger(chart_id,name,OBJPROP_STATE,false); // состояние кнопки (нажата/отжата) ObjectSetInteger(chart_id,name,OBJPROP_ZORDER,z_order); // приоритет выше/ниже ObjectSetString(chart_id,name,OBJPROP_TOOLTIP,"\n"); // без всплывающей подсказки, если "\n" } }
Чтобы было повеселей, цвет для каждой кнопки будет выбираться случайным образом. Для этого напишем простую функцию GetRandomColor():
//+------------------------------------------------------------------+ //| Возвращает случайный цвет | //+------------------------------------------------------------------+ color GetRandomColor() { //--- Выберем случайный цвет от 0 до 25 switch(MathRand()%26) { case 0 : return(clrOrange); break; case 1 : return(clrGold); break; case 2 : return(clrChocolate); break; case 3 : return(clrChartreuse); break; case 4 : return(clrLime); break; case 5 : return(clrSpringGreen); break; case 6 : return(clrMediumBlue); break; case 7 : return(clrDeepSkyBlue); break; case 8 : return(clrBlue); break; case 9 : return(clrSeaGreen); break; case 10 : return(clrRed); break; case 11 : return(clrSlateGray); break; case 12 : return(clrPeru); break; case 13 : return(clrBlueViolet); break; case 14 : return(clrIndianRed); break; case 15 : return(clrMediumOrchid); break; case 16 : return(clrCrimson); break; case 17 : return(clrMediumAquamarine); break; case 18 : return(clrDarkGray); break; case 19 : return(clrSandyBrown); break; case 20 : return(clrMediumSlateBlue); break; case 21 : return(clrTan); break; case 22 : return(clrDarkSalmon); break; case 23 : return(clrBurlyWood); break; case 24 : return(clrHotPink); break; case 25 : return(clrLightSteelBlue); break; //--- default : return(clrGold); } //--- return(clrGold); }
Теперь, напишем функцию SetSoundPanel(), которая будет устанавливать звуковую панель на график:
//+------------------------------------------------------------------+ //| Добавляет звуковую панель на график | //+------------------------------------------------------------------+ void SetSoundPanel() { int column_count =0; // Счетчик столбцов int x_dist =10; // Отступ от левого края графика int y_dist =15; // Отступ от верхней части графика int x_size =100; // Ширина кнопок int y_size =20; // Высота кнопок color button_color =clrNONE; // Цвет кнопок //--- Установим объекты for(int i=0; i<ARRAY_SIZE; i++) { //--- Увеличим счетчик столбцов column_count++; //--- Получим цвет для кнопки button_color=GetRandomColor(); //--- Нарисуем кнопку CreateButton(0,0,sound_names[i],sound_texts[i], ANCHOR_LEFT_UPPER,CORNER_LEFT_UPPER,"Arial",8, clrWhite,button_color,button_color,x_size,y_size,x_dist,y_dist,1); //--- Если уже установлено две кнопки в этом ряду if(column_count==2) { x_dist=10; // Координату X вернем в исходное положение y_dist+=20; // Координату Y установим для следующего ряда column_count=0; // Обнулим счетчик } else //--- Установим координату X для следующей кнопки x_dist+=x_size; } //--- Обновим график ChartRedraw(0); }
Для удаления панели с графика будем использовать функции, представленные ниже:
//+------------------------------------------------------------------+ //| Удаляет информационную панель | //+------------------------------------------------------------------+ void DeleteSoundPanel() { //--- Удалить свойства позиции и их значения for(int i=0; i<ARRAY_SIZE; i++) DeleteObjectByName(name_sound_object[i]); //--- Перерисовать график ChartRedraw(); } //+------------------------------------------------------------------+ //| Удаляет объекты по имени | //+------------------------------------------------------------------+ void DeleteObjectByName(string name) { //--- Если объект найден if(ObjectFind(ChartID(),name)>=0) { //--- Если была ошибка при удалении, сообщим об этом if(!ObjectDelete(ChartID(),name)) Print("Ошибка ("+IntegerToString(GetLastError())+") при удалении объекта!"); } }
Итак, при загрузке эксперта в функции OnInit() панель будет установлена на график, а при удалении эксперта в функции OnDeinit() панель будет удалена.
//+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ void OnInit() { //--- Установим звуковую панель SetSoundPanel(); } //+------------------------------------------------------------------+ //| Deinitialization function of the expert | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Удалим звуковую панель DeleteSoundPanel(); }
Осталось настроить взаимодействие с панелью, чтобы при нажатии на кнопки воспроизводились соответствующие им звуки. Чтобы не умереть со скуки сделаем еще так, чтобы при нажатии на одну из кнопок звуковой панели, цвета кнопок изменялись. Для этого нам понадобится функция ChangeColorsOnSoundPanel(), код которой представлен ниже:
//+------------------------------------------------------------------+ //| Изменяет цвета на звуковой панели | //+------------------------------------------------------------------+ void ChangeColorsOnSoundPanel() { color clr=clrNONE; // Цвет кнопки //--- В цикле пройдем по всем кнопкам и изменим их цвет for(int i=0; i<ARRAY_SIZE; i++) { //--- Получим новый цвет clr=GetRandomColor(); //--- Установим цвет рамки ObjectSetInteger(0,sound_names[i],OBJPROP_BGCOLOR,clr); //--- Установим цвет фона ObjectSetInteger(0,sound_names[i],OBJPROP_BORDER_COLOR,clr); //--- Отжатое состояние кнопки ObjectSetInteger(0,sound_names[i],OBJPROP_STATE,false); //--- Обновим график ChartRedraw(0); //--- Подождем (задержка) 20 миллисекунд Sleep(20); } }
И, наконец, в функции OnChartEvent() нужно разместить вот такой код:
//+------------------------------------------------------------------+ //| Обработчик событий | //+------------------------------------------------------------------+ void OnChartEvent(const int id, // Идентификатор события const long& lparam, // Параметр события типа long const double& dparam, // Параметр события типа double const string& sparam) // Параметр события типа string { //--- Если было событие "Нажатие левой кнопкой мыши на объекте" if(id==CHARTEVENT_OBJECT_CLICK) { //--- Если в имени объекта содержится "sound_button" if(StringFind(sparam,"sound_button",0)>=0) { //--- Воспроизведем звук по имени объекта // 5019 - ERR_FILE_NOT_EXIST - Файл не существует if(!PlaySound(GetSoundPath(sparam))) Print("Error: ",GetLastError()); //--- Изменим цвета всех кнопок ChangeColorsOnSoundPanel(); } } }
В коде выше в выделенной строке видно, что в функцию PlaySound() с помощью пользовательской функции GetSoundPath() передается путь, откуда будет взят звуковой файл. Ниже можно ознакомиться с кодом функции GetSoundPath():
//+------------------------------------------------------------------+ //| Возвращает путь к звуковому файлу по имени объекта | //+------------------------------------------------------------------+ string GetSoundPath(string object_name) { //--- Пройдемся в цикле по всем объектам звуковой панели for(int i=0; i<ARRAY_SIZE; i++) { //--- Если имя объекта, на который нажали на графике // совпадает с одним из тех, который есть в панели, вернем путь к файлу if(object_name==name_sound_object[i]) return(path_sound_object[i]); } //--- return(""); }
Теперь все готово. После набрасывания эксперта на график будет установлена звуковая панель (программу можно скачать в приложении к статье):
Рис. 2 - Звуковая панель на графике
Итак, принцип работы со звуковыми файлами теперь понятен. Теперь вернемся к нашему советнику из предыдущей статьи Рецепты MQL5 - Сохраняем результаты оптимизации торгового эксперта по указанным критериям и определимся со звуками, которые хотелось бы слышать в торговом эксперте. Создадим файл Resources.mqh и подключим его к основному файлу эксперта.
//--- Подключаем свои библиотеки #include "Include/Errors.mqh" #include "Include/Enums.mqh" #include "Include/Resources.mqh" #include "Include/TradeSignals.mqh" #include "Include/TradeFunctions.mqh" #include "Include/ToString.mqh" #include "Include/Auxiliary.mqh"
Выберем файлы для основных торговых событий.
//--- Звуковые файлы #resource "\\Files\\Sounds\\AHOOGA.WAV" // Ошибка #resource "\\Files\\Sounds\\CASHREG.WAV" // Открытие позиции/увеличение объема позиции/срабатывание отложенного ордера #resource "\\Files\\Sounds\\WHOOSH.WAV" // Установка/модификация отложенного ордера/Stop Loss/Take Profit #resource "\\Files\\Sounds\\VERYGOOD.WAV" // Закрытие позиции с прибылью #resource "\\Files\\Sounds\\DRIVEBY.WAV" // Закрытие позиции с убытком //--- Путь к звуковым файлам string SoundError = "::Files\\Sounds\\AHOOGA.WAV"; string SoundOpenPosition = "::Files\\Sounds\\CASHREG.WAV"; string SoundAdjustOrder = "::Files\\Sounds\\WHOOSH.WAV"; string SoundCloseWithProfit= "::Files\\Sounds\\VERYGOOD.WAV"; string SoundCloseWithLoss = "::Files\\Sounds\\DRIVEBY.WAV";
Хочу еще отметить, что помимо звуковых файлов в качестве ресурсов можно хранить в эксперте изображения в формате *.bmp для создания интерфейса, текстовые файлы и даже индикаторы. Эксперты для MetaTrader 5 теперь считаются вполне полноценными приложениями: это очень удобно, когда можно передать всего лишь один файл вместо нескольких.
Двигаемся дальше. Во внешних параметрах нужно добавить параметр UseSound, чтобы была возможность отключить воспроизведение звуков:
//--- Внешние параметры эксперта input int NumberOfBars =2; // Количество направленных баров sinput double Lot =0.1; // Лот input double TakeProfit =100; // Тейк Профит input double StopLoss =50; // Стоп Лосс input double TrailingStop =10; // Трейлинг Стоп input bool Reverse =true; // Разворот позиции sinput bool UseSound =true; // Звуковые оповещения
В файле Include\Enums.mqh создадим перечисление ENUM_SOUNDS для звуков.
//--- Звуки enum ENUM_SOUNDS { SOUND_ERROR =0, // Ошибка SOUND_OPEN_POSITION = 1, // Открытие позиции/увеличение объема позиции/срабатывание отложенного ордера SOUND_ADJUST_ORDER = 2, // Установка защитного стопа/уровня фиксации прибыли/отложенного ордера SOUND_CLOSE_WITH_PROFIT = 3, // Закрытие позиции с прибылью SOUND_CLOSE_WITH_LOSS = 4 // Закрытие позиции с убытком };
Эти идентификаторы понадобятся для пользовательской функции PlaySoundByID().
//+------------------------------------------------------------------+ //| Воспроизведение звука | //+------------------------------------------------------------------+ void PlaySoundByID(ENUM_SOUNDS id) { //--- Если это реал-тайм и звуки включены if(IsRealtime() && UseSound) { //--- Воспроизведем звук по переданному идентификатору switch(id) { case SOUND_ERROR : PlaySound(SoundError); break; case SOUND_OPEN_POSITION : PlaySound(SoundOpenPosition); break; case SOUND_ADJUST_ORDER : PlaySound(SoundAdjustOrder); break; case SOUND_CLOSE_WITH_PROFIT : PlaySound(SoundCloseWithProfit); break; case SOUND_CLOSE_WITH_LOSS : PlaySound(SoundCloseWithLoss); break; } } }
Во время торговых операций, которые совершает эксперт, звуковые эффекты можно воспроизводить, вызывая PlaySoundByID() из соответствующих торговых функций. Например, посмотрите, как это реализовано в функции OpenPosition():
//+------------------------------------------------------------------+ //| Открывает позицию | //+------------------------------------------------------------------+ void OpenPosition(double lot, ENUM_ORDER_TYPE order_type, double price, double sl, double tp, string comment) { //--- Установим номер мэджика в торговую структуру trade.SetExpertMagicNumber(0); //--- Установим размер проскальзывания в пунктах trade.SetDeviationInPoints(CorrectValueBySymbolDigits(10)); //--- Режим Instant Execution и Market Execution // *** Начиная с 803 билда, уровни Stop Loss и Take Profit *** // *** можно устанавливать при открытии позиции в режиме SYMBOL_TRADE_EXECUTION_MARKET *** if(symb.execution_mode==SYMBOL_TRADE_EXECUTION_INSTANT || symb.execution_mode==SYMBOL_TRADE_EXECUTION_MARKET) { //--- Если позиция не открылась if(!trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,comment)) { //--- Воспроизвести звук ошибки и вывести сообщение об этом PlaySoundByID(SOUND_ERROR); Print("Ошибка при открытии позиции: ",GetLastError()," - ",ErrorDescription(GetLastError())); } //--- Иначе воспроизвести звук открытия позиции else PlaySoundByID(SOUND_OPEN_POSITION); } }
В случае же, когда позиция закрывается по Stop Loss, Take Profit, вручную или любым другим способом, это событие нужно отслеживать в функции OnTrade(). Для этого напишем еще одну функцию SoundNotification(), в которой будут производиться необходимые проверки: если по текущему символу в истории сделок появилась новая сделка с идентификатором DEAL_ENTRY_OUT или DEAL_ENTRY_INOUT (полное/частичное закрытие позиции или разворот), то далее программа проверит, была ли закрыта эта сделка с прибылью или убытком, и воспроизведет соответствующий звук.
//+------------------------------------------------------------------+ //| Звуковое оповещение | //+------------------------------------------------------------------+ void SoundNotification() { //--- Если реал-тайм и включен звук if(IsRealtime() && UseSound) { ulong ticket =0; // Тикет сделки int total =0; // Общее кол-во сделок static ulong last_ticket =0; // Последний тикет до этой проверки //--- Получим всю историю if(!HistorySelect(0,TimeCurrent()+1000)) return; //--- Получим количество сделок в полученном списке total=HistoryDealsTotal(); //--- В полученном списке пройдемся по всем сделкам: от последней к первой for(int i=total-1; i>=0; i--) { //--- Если тикет сделки по ее позиции в списке получен if((ticket=HistoryDealGetTicket(i))>0) { //--- получим символ сделки GetHistoryDealProperties(ticket,D_SYMBOL); //--- Если символ сделки и текущий символ равны if(deal.symbol==_Symbol) { //--- получим направление сделки GetHistoryDealProperties(ticket,D_ENTRY); //--- Если это закрытие позиции, сокращение объема или разворот if(deal.entry==DEAL_ENTRY_OUT || deal.entry==DEAL_ENTRY_INOUT) { //--- Если тикет текущей сделки из списка (последняя сделка символа) равен предыдущему // или это инициализация тикета последней сделки if(ticket==last_ticket || last_ticket==0) { //--- Запомним тикет и выйдем last_ticket=ticket; return; } //--- Получим результат сделки GetHistoryDealProperties(ticket,D_PROFIT); //--- Если прибыль if(deal.profit>=0) { //--- Звук прибыли PlaySoundByID(SOUND_CLOSE_WITH_PROFIT); //--- Сохраним номер тикета last_ticket=ticket; return; } //--- Если убыток if(deal.profit<0) { //--- Звук убытка PlaySoundByID(SOUND_CLOSE_WITH_LOSS); //--- Сохраним номер тикета last_ticket=ticket; return; } } } } } } }
Функцию SoundNotification() нужно разместить в функциях OnInit() и OnTrade():
//+------------------------------------------------------------------+ //| Инициализация | //+------------------------------------------------------------------+ int OnInit() { //--- Инициализируем новый бар CheckNewBar(); //--- Инициализация тикетов последних сделок символа SoundNotification(); //--- Инициализация прошла успешно return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Отслеживание торговых событий | //+------------------------------------------------------------------+ void OnTrade() { //--- Звуковое оповещение SoundNotification(); }
Также воспроизведение звука было добавлено в конец функции ModifyTrailingStop() при модификации защитного уровня.
//+------------------------------------------------------------------+ //| Изменяет уровень Trailing Stop | //+------------------------------------------------------------------+ void ModifyTrailingStop() { //--- Если включен трейлинг и StopLoss if(TrailingStop>0 && StopLoss>0) { double new_sl =0.0; // Для расчета нового уровня Stop loss bool condition =false; // Для проверки условия на модификацию //--- Получим флаг наличия/отсутствия позиции pos.exists=PositionSelect(_Symbol); //--- Если есть позиция if(pos.exists) { //--- Получим свойства символа GetSymbolProperties(S_ALL); //--- Получим свойства позиции GetPositionProperties(P_ALL); //--- Получим уровень для Stop Loss new_sl=CalculateTrailingStop(pos.type); //--- В зависимости от типа позиции проверим соответствующее условие на модификацию Trailing Stop switch(pos.type) { case POSITION_TYPE_BUY : //--- Если новое значение для Stop Loss выше, // чем текущее значение плюс установленный шаг condition=new_sl>pos.sl+CorrectValueBySymbolDigits(TrailingStop*symb.point); break; case POSITION_TYPE_SELL : //--- Если новое значение для Stop Loss ниже, // чем текущее значение минус установленный шаг condition=new_sl<pos.sl-CorrectValueBySymbolDigits(TrailingStop*symb.point); break; } //--- Если Stop Loss есть, то сравним значения перед модификацией if(pos.sl>0) { //--- Если выполняется условие на модификацию ордера, т.е. новое значение ниже/выше, // чем текущее, модифицируем защитный уровень позиции if(condition) { if(!trade.PositionModify(_Symbol,new_sl,pos.tp)) Print("Ошибка при модификации позиции: ",GetLastError()," - ",ErrorDescription(GetLastError())); } } //--- Если Stop Loss нет, то просто установим его if(pos.sl==0) { if(!trade.PositionModify(_Symbol,new_sl,pos.tp)) Print("Ошибка при модификации позиции: ",GetLastError()," - ",ErrorDescription(GetLastError())); } } } //--- Звук модификации ордера PlaySoundByID(SOUND_ADJUST_ORDER); }
Заключение
На этом все. Все файлы для тестов можно скачать в приложении к статье. По теме звуков в терминале хочется также отметить одно интересное решение в Code Base CMIDI (автор Integer): с его помощью в MetaTrader 5 можно воспроизводить MIDI-файлы. Успехов!
![Технические индикаторы как цифровые фильтры](https://c.mql5.com/2/0/Indicators_as_digital_filters_MQL5.png)
![Итоги MetaTrader AppStore за 3 квартал 2013 года](https://c.mql5.com/2/0/avatar3.png)
![Рецепты MQL5 - Наблюдение за несколькими таймфреймами в одном окне](https://c.mql5.com/2/0/avatar__9.png)
![Рецепты MQL5 - Сохраняем результаты оптимизации торгового эксперта по указанным критериям](https://c.mql5.com/2/0/avatar__7.png)
![MQL5 - Язык торговых стратегий для клиентского терминала MetaTrader 5](https://c.mql5.com/i/registerlandings/logo-2.png)
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Думаю тема озвучивания торговых событий, на самом деле довольно интересная и полезная как и ваша статья, спасибо за информацию.
Однако современные средства мультимедиа уже далеко продвинулись после простой оцифровки звуков WAV, возьмите хоть Microsoft Speech, давно доступно в Windows и его эффективно можно применять.
Например, предлагаемые вами звуки торговых событий, логично было бы снабдить конкретными голосовыми комментами со значениями прибылей убитков и.т.д., с рекомендациями и советами.
Должны же советники, когда нибудь начать советовать нам, нормальным, человеческим языком...)
Главное, что для этого не требуется писать сложный программный код.
Кто читал мою статью и установил Hlaiman EA Generator, может проверить работу этого кода, скопировав и запустив его в файле, например - hello.vbs.Чтоб не быть голословным, привожу пример бейсик скрипта для речевого синтеза тестовой строки "HELLO WORLD!" по технологии MS Agent, выполняемой через Hlaiman движок.
Аналогичные файлы с различными текстовыми сообщениями можно создавать и использовать наряду с *.wav файлами для настройки событий МТ терминала, кроме того этот вызов, не сложно интегрировать непосредственно в MQL код.
...
Например, предлагаемые вами звуки торговых событий, логично было бы снабдить конкретными голосовыми комментами со значениями прибылей убитков и.т.д., с рекомендациями и советами.
Должны же советники, когда нибудь начать советовать нам, нормальным, человеческим языком...)
...
Статья, как всегда, является простым примером. Мне например нравится программа FL Studio 11. Можно синтезировать любой звук. Или сначала записать (в том числе и голос), а потом качественно обработать.