Содержание
Доброго времени суток!
Предположим, что у нас есть ручная торговая система, cостоящая из нескольких индикаторов, каждый из которых дает свой сигнал на вход. Нам нужно проанализировать эту ТС на десятке валютных пар, чтобы найти точку входа в рынок. Согласитесь, вручную это делать проблематично, нужно каждый раз пересматривать каждый чарт в поисках заветного входа. Давайте же упростим это действие, создав панель, которая будет отображать всю необходимую информацию о торговле на одном графике.
Создаем информационную панель
Для начала нам необходимо придумать какую либо ТС. Для этого примера я решил использовать данные трех простых индикаторов: MA, RSI и Bollinger Bands.
Логика данной ТС будет следующая:
- Если Moving Average указанного периода выше текущей цены — сигнал на продажу. Если ниже — на покупку.
- Если RSI находится выше отметки 60 (т.е. в зоне перекупленности) — сигнал на продажу. Если ниже 40 (т.е. в зоне перепроданности) — на покупку.
- Если цена пересекла верхнюю линию BB, либо отходит от нее не больше, чем на 30% от всей ширины канала — сигнал на продажу. Если же цена пересекла нижнюю линию BB, либо рядом с ней, но не более 30% от всей ширины канала — сигнал на покупку.
Для создания кода данных условий вполне достаточно. Результат будет отображаться стрелками с направлением вверх, вниз или вправо при сигналах на покупку, продажу или забор. Также мы будем учитывать значение спреда для каждого символа, чтобы было нагляднее.
Стоит уточнить, что данную ТС я взял из головы, она не проверена в работе на рынке и служит только для примера написания информационной панели.
Что ж, создаем пользовательский индикатор с отображением на графике. Нам нужно задать внешние параметры для последующей точечной настройки их. Для этого необходимо определиться с количеством валютных пар, которые нужно проанализировать с целью поиска сигнала. Возьмем девять пар. Для индикаторов нужно указать настройки периода, а также отклонение для BB.
0 1 2 3 4 |
extern string AllSymbols = "EURUSD,AUDUSD,CADJPY,NZDCAD,EURCHF,EURCAD,GBPAUD,GBPUSD,EURGBP"; extern int MA_Period = 200; extern int RSI_Period = 14; extern int BB_Period = 20; extern int BB_Deviation = 2; |
Вводим переменную PipsDivided на глобальном уровне, а также массив SymbolsList, который в последствии будет содержать в себе наш список пар.
0 1 |
string SymbolsList[]; int PipsDivided = 1; |
Переходим к функции обработки событий OnInit. Делаем проверку на количество знаков у брокера, а также смотрим, чтобы список пользовательских пар не был пустой.
0 1 |
if(Digits == 3 || Digits == 5) PipsDivided = 10; if(AllSymbols == "") { Print("Список символов пуст"); return(INIT_FAILED); |
Далее нам необходимо переписать данные стринговой переменной AllSymbols в пользовательский массив. Для этого вначале нужно воспользоваться строковой функцией StringSplit, чтобы разбить текст на элементы с указанным разделителем. В нашем случае разделитель это знак запятой «,». Его необходимо перевести в целый тип данных ushort с помощью функции StringGetCharacter.
0 1 2 |
string result[]; ushort u_sep=StringGetCharacter(",",0); int k=StringSplit(AllSymbols,u_sep,result); |
Нами получен массив result, содержащий список пар и переменная k, которая хранит в себе размер этого массива. Но это не все, нам необходимо обработать каждый символ, ведь в нем могут содержаться лишние пробелы, каретки, либо же буквы могут быть строчные. Для этого циклом пробегаем по значениям массива result, удаляем возможные лишние символы с помощью функций StringTrimLeft и StringTrimRight, а также переводим все буквы в прописные, воспользовавшись функцией StringToUpper. Обработанные данные переносим в массив SymbolsList.
Понятно, что если вы сами будете задать список пар, то скорее всего все будет корректно. Но если же вы передадите этот код пользователю, который не знает, как правильно все указывать, возможны ошибки. Мы же учимся писать как для себя, как и для других трейдеров, которым данные продукт может попасть в руки.
Еще один важный аспект, который нельзя пропустить, это отображение символа из списка в окне «Обзор рынка». Ведь если его там не будет, мы не сможем получить котировки по этой паре. Для этого есть функция SymbolSelect, которая добавляет символ в список доступных пар. В итоге ниже у нас получится следующий код:
0 1 2 3 4 5 6 7 8 9 10 |
int SymbolsSize = 0; ArrayResize(SymbolsList,1); for(int l=0;l<k;l++) { string result1=StringTrimLeft(StringTrimRight(result[l])); StringToUpper(result1); SymbolsList[SymbolsSize] = result1; SymbolSelect(SymbolsList[SymbolsSize],true); ArrayResize(SymbolsList,ArraySize(SymbolsList)+1); SymbolsSize++; //увеличиваем счетчик массива } |
Следующим шагом будет создание границ таблицы в виде прямоугольного лейбла, а также заголовков для нее. Т.к. эти графические элементы нужно создать всего один раз и больше не обновлять, то вызов пользовательских функций построения объектов происходит в функции OnInit. Но предварительно нужно создать их.
Создаем функцию построения прямоугольного лейбла:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
bool RectLabelCreate(const long chart_ID = 0, // ID графика const string name = "RectLabel", // имя метки const int sub_window = 0, // номер подокна const int x = 0, // координата по оси X const int y = 0, // координата по оси Y const int width = 50, // ширина const int height = 18, // высота const color back_clr = C'236,233,216', // цвет фона const ENUM_BORDER_TYPE border = BORDER_RAISED, // тип границы const ENUM_BASE_CORNER _corner = CORNER_LEFT_UPPER, // угол графика для привязки const color clr = clrRed, // цвет плоской границы (Flat) const ENUM_LINE_STYLE style = STYLE_SOLID, // стиль плоской границы const int line_width = 1) // толщина плоской границы { ResetLastError(); //--- сбросим значение ошибки if(ObjectFind(chart_ID,name) == -1) { if(!ObjectCreate(chart_ID,name,OBJ_RECTANGLE_LABEL,sub_window,0,0)) { //--- создадим прямоугольную метку Print(__FUNCTION__,": не удалось создать прямоугольную метку! " + IntegerToString(GetLastError())); return(false); } } ObjectSetInteger(chart_ID,name,OBJPROP_XDISTANCE,x); ObjectSetInteger(chart_ID,name,OBJPROP_YDISTANCE,y); ObjectSetInteger(chart_ID,name,OBJPROP_XSIZE,width); ObjectSetInteger(chart_ID,name,OBJPROP_YSIZE,height); ObjectSetInteger(chart_ID,name,OBJPROP_BGCOLOR,back_clr); ObjectSetInteger(chart_ID,name,OBJPROP_BORDER_TYPE,border); ObjectSetInteger(chart_ID,name,OBJPROP_CORNER,_corner); ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr); ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style); ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,line_width); return(true); } |
Пишем функцию создания текстовой метки:
0 1 2 3 4 5 6 7 8 9 10 |
void out_Label(string name, string text, string font, int X, int Y, int font_size, color col) { if(ObjectFind(name) < 0) { ObjectCreate(0,name,OBJ_LABEL,0,0,0); ObjectSetInteger(0,name,OBJPROP_CORNER,0); ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false); ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_CENTER); ObjectSetInteger(0,name,OBJPROP_XDISTANCE,X); ObjectSetInteger(0,name,OBJPROP_YDISTANCE,Y); } ObjectSetText(name,text,font_size,font,col); } |
Код вызова функций для построения графических объектов будет следующим:
0 1 2 3 4 5 6 |
RectLabelCreate(0,"DV|Rect1",0,5,16,300,ArraySize(SymbolsList)*30,clrDarkSlateGray,1,0); out_Label("DV|Title0","Symbol","Arial",40,30,10,clrWheat); out_Label("DV|Title1","Spread","Arial",100,30,10,clrWheat); out_Label("DV|Title2","MA","Arial",160,30,10,clrWheat); out_Label("DV|Title3","RSI","Arial",220,30,10,clrWheat); out_Label("DV|Title4","BB","Arial",280,30,10,clrWheat); |
В первой функции RectLabelCreate создается объект с именем «DV|Rect1″ по заранее определенным мною координатам Х и Y с уже заданной шириной и высотой. Цвет темно серый, тип рамки BORDER_RAISED и левый верхний угол привязки. т.е. ноль. Пять функций out_Label создают заголовки с заданным именем объекта, текстом, типом шрифта, координатами и цветом. Расположение элементов на графике по Х и Y подбирается скрупулёзно вручную. Т.е. указываются цифры по обоим осям, смотрится, как это выглядит в терминале и при необходимости значения правятся.
В итоге полностью функция OnInit будет будет иметь вид:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
int OnInit() { if(Digits == 3 || Digits == 5) PipsDivided = 10; if(AllSymbols == "") { Print("Список символов пуст"); return(INIT_FAILED); } string result[]; ushort u_sep=StringGetCharacter(",",0); int k=StringSplit(AllSymbols,u_sep,result); int SymbolsSize = 0; ArrayResize(SymbolsList,1); //преобразуем список пар в массив for(int l=0;l<k;l++) { string result1=StringTrimLeft(StringTrimRight(result[l])); StringToUpper(result1); SymbolsList[SymbolsSize] = result1; SymbolSelect(SymbolsList[SymbolsSize],true); ArrayResize(SymbolsList,ArraySize(SymbolsList)+1); SymbolsSize++; } //Создаем прямоугольник для фона таблицы RectLabelCreate(0,"DV|Rect1",0,5,16,300,ArraySize(SymbolsList)*30,clrDarkSlateGray,1,0); //создаем текстовые лейблы наименования шапки out_Label("DV|Title0","Symbol","Arial",40,30,10,clrWheat); out_Label("DV|Title1","Spread","Arial",100,30,10,clrWheat); out_Label("DV|Title2","MA","Arial",160,30,10,clrWheat); out_Label("DV|Title3","RSI","Arial",220,30,10,clrWheat); out_Label("DV|Title4","BB","Arial",280,30,10,clrWheat); return(INIT_SUCCEEDED); } |
А промежуточный код индикатора будет выглядеть на графике так:
Раз мы создаем графические элементы, которые будут отображаться на чарте, значит мы должны не забыть их удалить после снятия индикатора с графика во время деинициализации. Для этого создадим уже знакомую по прошлым урокам пользовательскую функцию ObjectsDelete.
0 1 2 3 4 |
void ObjectsDelete(string search) { for(int i = ObjectsTotal() - 1; i >= 0; i--) { if(StringFind(ObjectName(i), search) != -1) ObjectDelete(ObjectName(i)); } } |
Объявляется она в функции OnDeinit. Общий текст в имени всех наших объектов будет «DV|», т.е. сокращение от названия нашего проекта DaVinci FX. Соответственно, все элементы с этим текстом будут сразу же удалены после снятия советника с графика, тогда как остальные пользовательские элементы останутся не тронутыми.
0 1 2 3 |
void OnDeinit(const int reason) { ObjectsDelete("DV|"); //удаляем все наши объекты с графика } |
Пишем код расчета индикаторов с дальнейшим построением лейблов
Переходим к функции OnCalculate. В ней будет выполняться расчет данных индикаторов и обновление их на графике каждый тик. При построении и смещении лейблов на графике нам нужны координаты Х и Y, которые будут меняться по мере перехода к новой строке/колонке. Зададим их.
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
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[]) { int Y0 = 60; int X0 = 40, X_ = 40; return(rates_total); } |
Далее создаем цикл for, чтобы пробежаться по всем символам из нашего списка. Внутри цикла объявляем функцию создания лейбла с наименованием валютных пар по списку.
0 1 2 3 4 5 6 7 8 |
for(int j=0;j<ArraySize(SymbolsList)-1;j++) { out_Label("DV|Symbol "+IntegerToString(j),SymbolsList[j],"Arial",X_,Y0,10,clrSkyBlue); X_ += 60; //сдвиг на следующую колонку вправо ... //будущий код X_ = X0; //возвращаем координату X в первоначальное положение Y0 += 30; //отступ вниз по оси Y после построения объектов для одной пары } |
После создания лейбла в функции out_Label нам необходимо переместиться на следующую колонку, для этого к координате X_ прибавляется 60 пикселей. В конце всего цикла мы возвращаем X_ в положение начала таблицы, а Y0 сдвигаем на строчку вниз для новой пары.
Продолжаем заполнять тело цикла for расчетами для каждой колонки по очереди: Spread, MA, RSI и BB. Дальнейший код пишем вместо трех точек, что я указал выше. Начнем с расчета спреда. Создаем переменную Spread и узнаем его значение через функцию MarketInfo. Поделим полученное значение на переменную PipsDivided, чтобы преобразовать его в старые пункты. Чтобы зрительно видеть максимально допустимый спред разделим цвет лейблов на красный и зеленый. Допустим, что при спреде ниже или равен 1.5 пункта лейбл должен сигнализировать о том, что условия входа в сделку благоприятные. А при значении выше — цвет будет красный.
0 1 2 3 |
double Spread = NormalizeDouble(MarketInfo(SymbolsList[j],MODE_SPREAD)/PipsDivided,1); if(Spread <= 1.5) out_Label("DV|Spread "+IntegerToString(j),DoubleToString(Spread,1),"Arial",X_,Y0,10,clrLime); else out_Label("DV|Spread "+IntegerToString(j),DoubleToString(Spread,1),"Arial",X_,Y0,10,clrRed); X_ += 60; //сдвиг на следующую колонку вправо |
Если спред по всем вашим парам завышен, подумайте о новом, более подходящем брокере.
Скомпилируйте полученный код, индикатор должен отобразить следующее:
Переходим на строчку ниже. Теперь нам нужно получить данные трех индикаторов по очереди. Все данные будем брать с текущей, открытой свечи. Начнем со скользящей средней.
Ее тип будет SMA, построение по цене закрытия, период будет считываться из настроек. Соответственно у нас может быть три условия:
- Если МА выше текущей цены с отступом в 5 пунктов — сигнал на продажу.
- Если МА ниже текущей цены с отступом в 5 пунктов — сигнал на покупку.
- Если МА находится рядом с ценой — пропускаем сигнал.
В зависимости от полученного значения у нас будет отображаться красная стрелка вниз, зеленая вверх, либо серая вправо. Для того, чтобы вместо текста лейбл рисовал стрелку, нужно преобразовать код символа в односимвольную строку. Для этого есть функция CharToStr, внутри которой указывается номер символа из семейства шрифтов Wingdings.
Показания индикатора Moving Average мы получаем с помощью уже известной нам встроенной функции iMA. В параметры передаем текущий символ из массива, текущий таймфрейм (т.е. ноль), период из внешних настроек, метод усреднения SMA и цену закрытия для расчета. Данные будут браться для текущего (нулевого) бара.
0 1 2 3 4 5 6 7 |
//определяем данные по индикатору МА double MA = iMA(SymbolsList[j],0,MA_Period,0,MODE_SMA,PRICE_CLOSE,0); if(MA > iClose(SymbolsList[j],0,0) + 5*Point*PipsDivided) //если МА выше цены то стрелка вниз out_Label("DV|MA "+IntegerToString(j),CharToStr(242),"Wingdings",X_,Y0,15,clrRed); else if(MA < iClose(SymbolsList[j],0,0) - 5*Point*PipsDivided) //если МА ниже цены то стрелка вверх out_Label("DV|MA "+IntegerToString(j),CharToStr(241),"Wingdings",X_,Y0,15,clrLime); else out_Label("DV|MA "+IntegerToString(j),CharToStr(240),"Wingdings",X_,Y0,15,clrGray); X_ += 60; //сдвиг на следующую колонку вправо |
Как я уже говорил, после работы с колонкой одного индикатора необходимо делать отступ по оси X, чтобы перейти к следующей колонке. В нашем случае это 60 пикселей. Также, если вас не устраивают внешний вид выбранных мною стрелочек направления сигнала, вы можете заменить их на номера 224, 225 и 226, либо вообще отобрать свой набор символов из таблицы шрифта Wingdings.
Переходим к созданию второго индикатора. Для чтения данных RSI мы воспользуемся функцией iRSI. Нам нужно задать также символ из массива, текущий ТФ, период из внешних настроек и цену закрытия. Расчет идет также по текущей цене. По условиям стратегии у нас может быть три варианта:
- Значение линии индикатора больше или равно 60. Тогда сигнал на продажу и стрелочку создаем с направлением вниз красного цвета.
- Значение линии индикатора меньше или равно 40. Тогда сигнал на покупку и стрелочку создаем с направлением вверх зеленого цвета.
- Иное. Если ни одно из двух условий не совпадет, то создается горизонтальная стрелка серого цвета — сигнала нет.
0 1 2 3 4 5 |
//определяем данные по индикатору RSI double RSI = iRSI(SymbolsList[j],0,RSI_Period,PRICE_CLOSE,0); if(RSI >= 60) out_Label("DV|RSI "+IntegerToString(j),CharToStr(242),"Wingdings",X_,Y0,15,clrRed); else if(RSI <= 40) out_Label("DV|RSI "+IntegerToString(j),CharToStr(241),"Wingdings",X_,Y0,15,clrLime); else out_Label("DV|RSI "+IntegerToString(j),CharToStr(240),"Wingdings",X_,Y0,15,clrGray); X_ += 60; //сдвиг на следующую колонку вправо |
Сделали отступ по оси Х и сразу дописываем строки для расчета последнего индикатора Bollinger Bands. Данный трендовый индикатор создает три линии: центральную, созданную по данными Moving Averages и две линии над и под ним с указанным отклонением. Нам нужны две линии канала. Создадим две переменные и с помощью функции iBands получим необходимые значения. Задаем следующие параметры: символ из массива, ТФ, период индикатора и отклонения из внешних переменных, нулевой сдвиг, цену закрытия для расчета и индекс линии индикатора. В нашем случае это две константы MODE_UPPER и MODE_LOWER для верхней и нижней линии канала соответственно.
0 1 2 |
//определяем данные по индикатору BB double BB_up = iBands(SymbolsList[j],0,BB_Period,BB_Deviation,0,PRICE_CLOSE,MODE_UPPER,0); double BB_dn = iBands(SymbolsList[j],0,BB_Period,BB_Deviation,0,PRICE_CLOSE,MODE_LOWER,0); |
Условие входа, которое я писал вначале немного сумбурное, но так даже интереснее. Для сигнала на продажу мы учитываем два условия на выбор:
- Чтобы цена пересекла границу верхнего канала и была выше его.
- Чтобы цена располагалась внутри канала, но на расстоянии в заданном пределе от верхней границы. Будем использовать процент расстояния от этой границы до нижнего канала. Т.е. если представить, что ширина всего канала равна 100%, то для сигнала в продажу наша цена должна отходить от верхнего канала не больше, чем на 30%. Для наглядности скриншот:
Для сигнала по покупку все наоборот — цена должна либо пересечь нижний канал, либо находиться рядом с ним, но не дальше, чем на 30% от ширины всего канала.
Если оба условия не срабатывают, значит сигнала нет и мы создаем горизонтальную стрелку серого цвета.
0 1 2 3 4 |
if((iClose(SymbolsList[j],0,0) >= BB_up) || (BB_up-iClose(SymbolsList[j],0,0))*100/(BB_up-BB_dn) < 30) out_Label("DV|BB "+IntegerToString(j),CharToStr(242),"Wingdings",X_,Y0,15,clrRed); else if((iClose(SymbolsList[j],0,0) <= BB_dn) || (iClose(SymbolsList[j],0,0)-BB_dn)*100/(BB_up-BB_dn) < 30) out_Label("DV|BB "+IntegerToString(j),CharToStr(241),"Wingdings",X_,Y0,15,clrLime); else out_Label("DV|BB "+IntegerToString(j),CharToStr(240),"Wingdings",X_,Y0,15,clrGray); //нет сигнала |
После данных расчетов у нас происходит замена значений координат Х и Y, которые мы создали в самом начале, чтобы на следующей итерации цикла мы продолжили заполнение таблицы для других символов из массива.
В итоге тело заполненной функции OnCalculate будет иметь вид:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
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[]) { //задаем начальные координаты для построения панели int Y0 = 60; int X0 = 40, X_ = 40; //делаем цикл по каждому символу отдельно для перебора всех валютных пар for(int j=0;j<ArraySize(SymbolsList)-1;j++) { out_Label("DV|Symbol "+IntegerToString(j),SymbolsList[j],"Arial",X_,Y0,10,clrSkyBlue); X_ += 60; //определяем спред для каждой пары double Spread = NormalizeDouble(MarketInfo(SymbolsList[j],MODE_SPREAD)/PipsDivided,1); if(Spread <= 1.5) out_Label("DV|Spread "+IntegerToString(j),DoubleToString(Spread,1),"Arial",X_,Y0,10,clrLime); else out_Label("DV|Spread "+IntegerToString(j),DoubleToString(Spread,1),"Arial",X_,Y0,10,clrRed); X_ += 60; //определяем данные по индикатору МА double MA = iMA(SymbolsList[j],0,MA_Period,0,MODE_SMA,PRICE_CLOSE,0); if(MA > iClose(SymbolsList[j],0,0) + 5*Point*PipsDivided) //если МА выше цены то стрелка вниз out_Label("DV|MA "+IntegerToString(j),CharToStr(242),"Wingdings",X_,Y0,15,clrRed); else if(MA < iClose(SymbolsList[j],0,0) - 5*Point*PipsDivided) //если МА ниже цены то стрелка вверх out_Label("DV|MA "+IntegerToString(j),CharToStr(241),"Wingdings",X_,Y0,15,clrLime); else out_Label("DV|MA "+IntegerToString(j),CharToStr(240),"Wingdings",X_,Y0,15,clrGray); X_ += 60; //определяем данные по индикатору RSI double RSI = iRSI(SymbolsList[j],0,RSI_Period,PRICE_CLOSE,0); if(RSI >= 60) out_Label("DV|RSI "+IntegerToString(j),CharToStr(242),"Wingdings",X_,Y0,15,clrRed); else if(RSI <= 40) out_Label("DV|RSI "+IntegerToString(j),CharToStr(241),"Wingdings",X_,Y0,15,clrLime); else out_Label("DV|RSI "+IntegerToString(j),CharToStr(240),"Wingdings",X_,Y0,15,clrGray); X_ += 60; //определяем данные по индикатору BB double BB_up = iBands(SymbolsList[j],0,BB_Period,BB_Deviation,0,PRICE_CLOSE,MODE_UPPER,0); double BB_dn = iBands(SymbolsList[j],0,BB_Period,BB_Deviation,0,PRICE_CLOSE,MODE_LOWER,0); if((iClose(SymbolsList[j],0,0) >= BB_up) || (BB_up-iClose(SymbolsList[j],0,0))*100/(BB_up-BB_dn) < 30) out_Label("DV|BB "+IntegerToString(j),CharToStr(242),"Wingdings",X_,Y0,15,clrRed); else if((iClose(SymbolsList[j],0,0) <= BB_dn) || (iClose(SymbolsList[j],0,0)-BB_dn)*100/(BB_up-BB_dn) < 30) out_Label("DV|BB "+IntegerToString(j),CharToStr(241),"Wingdings",X_,Y0,15,clrLime); else out_Label("DV|BB "+IntegerToString(j),CharToStr(240),"Wingdings",X_,Y0,15,clrGray); X_ = X0; Y0 += 30; } return(rates_total); } |
Законченная информационная панель будет выглядеть так:
Заключение
В этом уроке мы проделали множество действий для закрепления информации из ранних курсов: создание пользовательских функций, графических объектов типа OBJ_RECTANGLE_LABEL и OBJ_LABEL, импорт данных классических индикаторов в наш код. Создали условную стратегию для расчета данных по пользовательским параметрам.
Хотелось бы еще раз напомнить, что рассмотренная выше стратегия трех индикаторов не пригодна для торговли, это просто плод моей фантазии, целью которого была демонстрация возможностей языка MQL4. Вам же предоставляется скелет кода, в который можно добавить сколько угодно своих индикаторов для анализа именно вашей торговой системы.
Данным уроком я заканчиваю второй раздел, посвященный созданию индикаторов. Этот и предыдущие уроки вполне раскрывают возможности терминала в плане работы с ними. Следующий, третий раздел своего курса обучения языку MQL4 я посвящу созданию и работе с Советниками.
Хочу заменить, что мои уроки созданы для публикации только на сайте команды DaVinci FX Group и предоставляются бесплатно.
Подписывайтесь, если не хотите пропустить новые посты. Обещаю, лишнего спама вам на почту не придет 🙂
[download url=»http://www.davinci-fx.com/wp-content/uploads/2021/01/2.9-Signal-infopanel.rar» title=»Скачать код урока»]
4 комментария. Оставить новый
Привет, отличная статья.
К сожалению кнопка для скачивания кода не кликабельная.
Добрый день. Спасибо, поправили.
Здравствуйте.
Подскажите, есть ли возможность прокруткой мыши двигать по вертикали OBJ_RECTANGLE_LABEL
Спасибо.
Добрый день. Объект OBJ_RECTANGLE_LABEL привязан к графику по осям Х и Y, он не смещается при изменениях на графике.
Если вам нужен объект с привязкой к цене и времени, то используйте тип объекта OBJ_RECTANGLE