Философия MQL4

Программирование прибыли: от азов к секретам мастерства. Читайте, спрашивайте, делитесь опытом.
Бонус за сообщение 0.5$
Ответственный Модератор - Haos

Re: Философия MQL4

Сообщение mfcoder » 25 авг 2013, 19:59

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

Код: выделить все
int ar[10];
//здесь производится перемещение по индексам от 0 до 9 c занесением значения индекса в массив
for (int i = 0; i < ArraySize(ar); i++){// функция ArraySize() возвращает количество элементов массива
   ar[i] = i;// заполним i-й элемент массива соответствующим (i-тым же) значением индекса
}
// вывод значений массива на печать
for(i = 0; i < ArraySize(ar); i++){
   Print(i," = ", ar[i]);
}


для двумерного массива это будет выглядеть так

Код: выделить все
int ar[2][5];
// функция ArrayRange() возвращает количество элементов в указанной размерности массива,
// размерности как и индексы нумеруются с 0
for(int i = 0; i < ArrayRange(ar, 0); i++){ // индексы от 0 до 1 (2 элемента) первой размерности массива
   for(int j = 0; j < ArrayRange(ar, 1); j++){ // индексы от 0 до 4 (5 элементов) второй размерности массива
       Print("[",i,",",j,"] = ",j);
       ar[i][j] = j;
   }
}


в принципе двумерный массив можно представить как одномерный и использовать условное разделение на два, например,

Код: выделить все
int ar[10];
int mid = ArraySize(ar) / 2;
for (int i = 0; i < ArraySize(ar); i++) {
    ar[i] = i % mid;
    Print(i," = ", ar[i]);
}


этот блок будет подобен заполнению предыдущего массива ar[2][5], с той лишь разницей что он будет одномерным, и если мысленно склеить массив ar[2][5] построчно в один, то получится тот же результат что и в ar[10].. где-то такое удобно использовать, где-то нет.. важно понимать что нет принципиальной разницы между одномерным массивом и двумерным из одного и того же общего числа элементов... разница лишь в управлении элементами и обращениями к ним.. (отличия возможно чуть ниже по тексту получится привести)
Аватар пользователя
mfcoder
 
Сообщений: 1538
Зарегистрирован: 29 июл 2013, 11:55
Средств на руках: 26.85 Доллар
Группа: Базовая
Благодарил (а): 78 раз.
Поблагодарили: 423 раз.

Re: Философия MQL4

Сообщение mfcoder » 25 авг 2013, 19:59

немного об инициализации массивов
одномерные массивы могут объявляться без указания количества элементов
Код: выделить все
int a[];
int aa[] = {1, 2, 3}; // в фигурных скобках значения элементов массива
int aaa[][3] = {1, 2, 3, 11, 22, 33};// таким образом получим массив 2 на 3

таким образом можно не указывать количество элементов (в квадратных скобках), оно определится автоматически числом внесенных значений

или с указанием количества элементов
Код: выделить все
int b[2];


массивы с размерностями могут иметь неуказанное число элементов только в первой размерности
Код: выделить все
int c[][4];
int d[][2][3];
int e[][2][4][3];

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

в отличие от многих высокоуровневых языков программирования массивы не являются фиксированными по числу элементов, что означает возможность увеличения количества элементов массива, например,

изменить/задать размерности можно с помощью функции ArrayResize(), например,
Код: выделить все
ArrayResize(a, 10);// 10 элементов
ArrayResize(с, 3);// 3х4 = 12 элементов
ArrayResize(d, 4);// 4x2x3 = 24 элемента
ArrayResize(e, 3);// 3x2x4x3 = 72 элемента


собственно, массивы динамические по сути, т.е. с изменяемым (в сторону увеличения) числом элементов, например, найдем все числа от 1 до 1000, которые делятся на 13, их не много, но так сразу и не скажешь сколько их и какие они
Код: выделить все
int ar[];
    int dev = 13, // делитель
    size = 0; // количество элементов массива
   
    ArrayResize(ar, size);
    for (int i = 0; i <= 1000; i++){
        if (i % dev == 0){
            ArrayResize(ar, size + 1); // увеличиваем количество элементов массива на 1
            ar[size] = i; // в добавленный элемент заносим значение кратное dev без остатка   
            size++; // приводим параметр size к действительному значению элементов массива
            // более корректно было бы вместо size++; написать size = ArraySize(ar);
        }
    }
    for (i = 0; i < ArraySize(ar); i++){
        Print(i,": ", ar[i]);
    }


если обратить внимание на код, то там присутствует излишняя строка
Код: выделить все
ArrayResize(ar, size);


как бы
Код: выделить все
int ar[];

подразумевает, что размер массива и так имеет 0 элементов, однако это привычка оставшаяся как артефакт..
она появилась при написании не помню уже какого функционала, но суть в том, что в некоторой функции использовался массив какого-то размера, который задавался при инициализации, так вот алгоритм был какой-то кривенький и не все элементы массива заполнялись (а вычисления были по всем элементам), т.е. какие-то пропускались, как результат алгоритм работал неправильно, хотя по умолчанию если массив это числа и объявлен массив заданного размера, то все элементы в нем должны быть нули, и алгоритм это учитывал.. однако, как оказалось, что если функция вызывалась несколько раз, то в массив попадал всякий числовой мусор, и как результат считалось черте что, с тех пор я всегда зануляю массив и только после этого задаю его размер.. вот такая байка :).. попробую на досуге все же найти такую показательную ситуацию..
Аватар пользователя
mfcoder
 
Сообщений: 1538
Зарегистрирован: 29 июл 2013, 11:55
Средств на руках: 26.85 Доллар
Группа: Базовая
Благодарил (а): 78 раз.
Поблагодарили: 423 раз.

Re: Философия MQL4

Сообщение mfcoder » 26 авг 2013, 19:54

2. Создание индикаторов

пожалуй, сначала опишу основные сущности из чего состоит индикатор..
собственно, индикатор это программа с расширением mq4, которая должна находиться в каталоге experts\indicators вашего терминала
и так, индикатор определяется своими декларациями, а именно, обязательной декларацией является
Код: выделить все
#property indicator_chart_window

или
Код: выделить все
#property indicator_separate_window 
соответственно, первая говорит о том, что индикация выводится в основное окно с графиком, а вторая в дополнительное окно

далее следует декларация количества используемых индикаторных буферов с указанием количества используемых буферов (от 1 до 8)
Код: выделить все
#property indicator_buffers 1


эта декларация нужна, если данные для индикации предполагается выводить через индикаторные буферы, если же индикатор будет рисовать отдельные графические объекты (стрелки, линии и т.п.), то декларация не нужна

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

далее следуют параметры цвета выводимой индикации indicator_colorN, где номер буфера (от 1 до 8) с названием цвета
Код: выделить все
#property indicator_color1 Yellow
#property indicator_color2 Red

и т.д.

далее следуют какие-то глобальные и/или внешние параметры, например,
Код: выделить все
extern int drawBegin = 1000;
extern int shiftPrice = 10;


далее обязательны double массивы, в которые будут заноситься данные цен (или еще какие данные), по которым будет выводиться графическая информация, например,
Код: выделить все
double buff[];


теперь важный момент, все (почти все) начальные определения для используемых индикаторных буферов задаются в системной функции init()
рассмотрим это подробнее, и так по порядку, допустим мы создаем индикатор, который будет рисовать линию закрытия цен в основном окне, сам индикатор не несет ничего полезного, разве что понимание того что и как в нем устроено..
для такого индикатора потребуется один буфер, и соответственно, один массив типа double..
чтобы индикатор выводил нужную индикацию нужно задать настройки индикации - что есть что и как будет отображаться

назначаем 0-му индикаторному буферу массив, в котором будут храниться его данные
Код: выделить все
SetIndexBuffer(0, buff);


устанавливаем индикаторному буферу все значение в 0, т.е. все значения в buff будут нулями
это необязательная опция, она приведена для информации, иногда требуются определенные начальные значения в буфере
Код: выделить все
SetIndexEmptyValue(0, 0);


не обязательная опция
устанавливает номер бара, с которого необходимо начать рисовать индикацию
Код: выделить все
SetIndexDrawBegin(0, drawBegin);


не обязательная опция
устанавливаем подпись - название индикации, она отображается во всплывающем окошке когда подводишь курсор к индикации
Код: выделить все
SetIndexLabel(0, "наша цена");


устанавливаем тип отображаемой индикации, в данном случае линия, у функции SetIndexStyle() есть еще три необязательных параметра,
которые здесь не использованы, после типа индикации (DRAW_LINE) идут параметры стиль, толщина и цвет линии
кстати, наличие последнего параметра (цвета) отменяет необходимость объявлять параметр indicator_colorN
Код: выделить все
SetIndexStyle(0, DRAW_LINE);


не обязательная опция
сдвиг отображаемой индикации на shiftPrice баров влево, т.е. вся индикация сдвигается как бы shiftPrice
становится нулевым для отображаемой индикации - иначе говоря смена центра координат,
но только для отображения, в buff значения остаются на своих местах
Код: выделить все
SetIndexShift(0, shiftPrice);


в итоге имеет функцию init() вида
Код: выделить все
int init(){
    SetIndexBuffer(0, buff);
    SetIndexEmptyValue(0, 0);
    SetIndexDrawBegin(0, drawBegin);
    SetIndexLabel(0, "наша цена");
    SetIndexStyle(0, DRAW_LINE);
    SetIndexShift(0, shiftPrice);
}


далее осталось написать код функции start(), который будет обрабатывать данные и записывать их в массив buff, собственно, код простой
Код: выделить все
int bars = 0, // количество не обсчитанных баров
i = 0; // индекс дальнего (от текущего нулевого бара) не обсчитанного бара


количество не обсчитанных баров на текущем тике, по приходу первого тика после прикрепления индикатора к графику
функция IndicatorCounted() возвращает количество всех баров, которые доступны на текущем графике, т.к. их еще не считали
на последующих тиках функция возвращает 1, т.е. текущий не посчитанный бар, и только при появлении нового бара возвращает 2,
т.к. при закрытии бара и открытии нового и там и там было (могло быть) изменение цен
Код: выделить все
bars = IndicatorCounted();


такого быть в нормальных условиях быть не должно, т.к. всегда есть 1 бар - текущий, на котором изменилось значение,
и поэтому этот бар считается не обсчитанным, возможно, такая ситуация случается при разрывах соединения с сервером (?!)
Код: выделить все
if (bars < 0) return(-1);


здесь Bars это общее число баров на графике, т.е. от начала справа и до конца по истории влево,
и здесь мы вычисляем индекс, с которого начинаются не обсчитанные бары, последний член выражения (-1) используется из-за того,
что индексы начинаются с нуля, поэтому на один меньше
Код: выделить все
i = Bars - bars - 1;



// перебираем все не обсчитанные бары
Код: выделить все
while(i >= 0){
    // заносим в i-й элемент буфера цену закрытия на этом буфере
    buff[i] = Close[i];

    // уменьшаем индекс на единицу
    i--;
}


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

и так, получаем итоговый индикатор
Код: выделить все
#property indicator_chart_window   
#property indicator_buffers 1       
#property indicator_color1 Yellow   

extern int drawBegin = 1000;
extern int shiftPrice = 10;
double buff[];

int init(){
    SetIndexBuffer(0, buff);
    SetIndexEmptyValue(0, 0);
    SetIndexDrawBegin(0, drawBegin);
    SetIndexLabel(0, "наша цена");
    SetIndexStyle(0, DRAW_LINE);
    SetIndexShift(0, shiftPrice);
}

int start(){
    int bars = 0, i = 0;
   
    bars = IndicatorCounted();
    if (bars < 0) return(-1);
    i = Bars - bars - 1;   

    while(i >= 0){
        buff[i] = Close[i];
        i--;
    }
}


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

если что непонятно излагаю, уж извините за косность языка, но думаю это поправимо встречными вопросами с конкретикой где и что не понятно..
Аватар пользователя
mfcoder
 
Сообщений: 1538
Зарегистрирован: 29 июл 2013, 11:55
Средств на руках: 26.85 Доллар
Группа: Базовая
Благодарил (а): 78 раз.
Поблагодарили: 423 раз.

Re: Философия MQL4

Сообщение mfcoder » 12 сен 2013, 17:58

3. Использование графических объектов

сейчас мы немного отклонимся от программирования индикаторов, но тем не менее коснемся индикации как таковой..

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

все такие объекты создаются одной функцией
bool ObjectCreate( string name, int type, int window, datetime time1, double price1, datetime time2=0, double price2=0, datetime time3=0, double price3=0)

Параметры:
Код: выделить все
name   -   Уникальное имя объекта.
type   -   Тип объекта. Может быть любым из типов объектов.
window   -   Индекс окна, в которое будет добавлен объект. Индекс окна должен быть большим или равным 0 и меньшим, чем WindowsTotal().
time1   -   Время первой координаты.
price1   -   Цена первой координаты.
time2   -   Время второй координаты.
price2   -   Цена второй координаты.
time3   -   Время третьей координаты.
price3   -   Цена третьей координаты.


типов объектов (здесь я перечислю наиболее используемые, а с полным списком объектов можно ознакомиться в справке: Справочник MQL4 - Стандартные константы - Типы объектов)

OBJ_VLINE - Вертикальная линия. Использует время в качестве первой координаты, цена игнорируется
OBJ_HLINE - Горизонтальная линия. Использует цену в качестве первой координаты, время игнорируется
OBJ_TREND - Трендовая линия. Использует 2 координаты
OBJ_RECTANGLE - Прямоугольник. Использует 2 координаты
OBJ_TEXT - Текст. Использует 1 координату. Для установки угла выводимого текста (свойство OBJPROP_ANGLE) используется функция ObjectSet(). Для изменения текста используется функция ObjectSetText()
OBJ_LABEL - Текстовая метка. Не использует координат. Для установки координат, задаваемых в пикселях относительно угла привязки (свойства OBJPROP_CORNER, OBJPROP_XDISTANCE, OBJPROP_YDISTANCE) используется функция ObjectSet(). Для изменения текста используется функция ObjectSetText()
OBJ_ARROW - Стрелки (символы). Использует 1 координату. Для установки кода символа (свойство OBJPROP_ARROWCODE) используется функция ObjectSet()
OBJ_FIBO - Уровни Фибоначчи. Использует 2 координаты. Для установки количества уровней (свойство OBJPROP_FIBOLEVELS) и значения уровней (свойство OBJPROP_FIRSTLEVEL+n) используется функция ObjectSet()
Аватар пользователя
mfcoder
 
Сообщений: 1538
Зарегистрирован: 29 июл 2013, 11:55
Средств на руках: 26.85 Доллар
Группа: Базовая
Благодарил (а): 78 раз.
Поблагодарили: 423 раз.

Re: Философия MQL4

Сообщение mfcoder » 12 сен 2013, 18:06

3.1. Создание графических объектов

если обратить внимание на функцию создания объектов
bool ObjectCreate( string name, int type, int window, datetime time1, double price1, datetime time2=0, double price2=0, datetime time3=0, double price3=0)

то видно, что не все параметры являются обязательными (как мы помним из формата задания параметров функций - первые пять параметров являются обязательными, а остальные - необязательные) и в этом есть смысл, он будет понятен после рассмотрения создания отдельных типов/видов объектов..

примеры создания различных объектов:

3.1.2. Вывод текста

Код: выделить все
int window = 0; // 0 - окно с графиком, т.е. основное окно
string name = "какойТоТекст";
int objType = OBJ_TEXT; // тип создаваемого объекта -  текст
int time = Time[0]; // первая координата объекта - время, в данном случае время открытия нулевого бара
double price = Open[0]; // вторая координата объекта - цена, в данном случае цена открытия нулевого бара
ObjectCreate(name, OBJ_TEXT, window, time, price);


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

например, текст создалася с надписью Text, серого цвета, размер шрифта 10, а шрифт Arial, разумно было бы задавать такие параметры, т.к. раз что-то выводится, значит оно для чего-то нужно..

и так, опишем задание свойств выводимого объекта
Код: выделить все
string text = "а был ли мальчик";
color col = Green;
int fontsize = 9;
string fontname = "Tahoma";
ObjectSetText(name, text, fontsize, fontname, col);


после добавления последнего блока кода к предыдущему получим текст зеленого цвета, размером шрифта 9 и шрифтом тахома, а сам объект будет отображать текст а был ли мальчик
Аватар пользователя
mfcoder
 
Сообщений: 1538
Зарегистрирован: 29 июл 2013, 11:55
Средств на руках: 26.85 Доллар
Группа: Базовая
Благодарил (а): 78 раз.
Поблагодарили: 423 раз.

Re: Философия MQL4

Сообщение mfcoder » 12 сен 2013, 19:53

3.1.3. Создание текстовой метки

текстовая метка отличается от объекта текст параметрами, а именно, текст создается по координатам цены/времени, т.е. по данным ценового ряда.. текстовая метка создается по координатам экрана, т.е. задается {X, Y} в пикселях от одного из четырех углов экрана (имеется в виду активное окно/подокно терминала)..

таким образом, текст будет перемещаться вместе с прокручиваемым графиком, а текстовая метка нет..
при создании метки мы применим ранее использовавшуюся функцию ObjectSetText(), а также используем новую функцию ObjectSet(), эта функция позволяет манипулировать с различными свойствами объектов

Код: выделить все
string name = "имяМетки";
int window = 0;
string text = "Номер счета: " + AccountNumber();
color col = Blue;
int corner = 1; // правый верхний угол, от которого будут открадываться координаты
int x = 100; // координата по горизонтали
int y = 100; // координата по вертикали
int fontsize = 9;
string fontname = "Tahoma";

ObjectCreate(name, OBJ_LABEL, window, 0, 0); // последние параметры - координаты цены/времени нули
ObjectSetText(name, text, fontsize, fontname, col);
ObjectSet(name, OBJPROP_CORNER, corner); // устанавливаем угол экрана, от которого будут откладываться x,y
ObjectSet(name, OBJPROP_XDISTANCE, x); // устанавливаем x координату
ObjectSet(name, OBJPROP_YDISTANCE, y); // устанавливаем у координату


в правой верхней части графика выводится метка Номер счета: 1001953198

в вашем случае номер счета конечно же будет другим, но думаю принцип создания объекта понятен
Аватар пользователя
mfcoder
 
Сообщений: 1538
Зарегистрирован: 29 июл 2013, 11:55
Средств на руках: 26.85 Доллар
Группа: Базовая
Благодарил (а): 78 раз.
Поблагодарили: 423 раз.

Re: Философия MQL4

Сообщение mfcoder » 12 сен 2013, 20:25

3.1.4. Создание объекта стрелка

стрелки создаются также по координатам цены/времени, для отображения объекта стрелка используются коды, которые соответствуют символам шрифта Wingdings, детали можно посмотреть в справке (Справочник MQL4 - Стандартные константы - Wingdings)

пример создания стрелки
Код: выделить все
string name = "стрелка";
 int window = 0;
 datetime time = Time[0];
 double price = Open[0];
 color col = Yellow;
 int arrIndex = 241; // код стрелки, показывающей вверх
 
 ObjectCreate(name, OBJ_ARROW, window, time, price);
 ObjectSet(name, OBJPROP_ARROWCODE, arrIndex);
 ObjectSet(name, OBJPROP_COLOR, col);


на нулевом баре по цене открытия будет создан графический объект в виде желтой стрелки, показывающей вверх :-):
Аватар пользователя
mfcoder
 
Сообщений: 1538
Зарегистрирован: 29 июл 2013, 11:55
Средств на руках: 26.85 Доллар
Группа: Базовая
Благодарил (а): 78 раз.
Поблагодарили: 423 раз.

Re: Философия MQL4

Сообщение mfcoder » 14 сен 2013, 12:53

3.1.5. Рисование линий

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

3.1.5.1. Вертикальная линия

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

создание линии выглядит nfr
Код: выделить все
string name = "вертикальная линия";
int window = 0;
datetime time1 = Time[0];
color col = Green;

ObjectCreate(name, OBJ_VLINE, window, time1, 0, 0, 0);
ObjectSet(name, OBJPROP_COLOR, col);


как можно увидеть здесь ничего нового нет, все просто и понятно
Аватар пользователя
mfcoder
 
Сообщений: 1538
Зарегистрирован: 29 июл 2013, 11:55
Средств на руках: 26.85 Доллар
Группа: Базовая
Благодарил (а): 78 раз.
Поблагодарили: 423 раз.

Re: Философия MQL4

Сообщение mfcoder » 14 сен 2013, 17:28

3.1.5.2. Создание горизонтальной линии

отличие от горизонтальной линии от вертикальной только в одной координате - вместо координаты времени используется координата цены

Код: выделить все
string name = "горизонтальная линия";
int window = 0;
double price = Open[0];
color col = Green;

ObjectCreate(name, OBJ_HILNE, window, 0, price, 0);
ObjectSet(name, OBJPROP_COLOR, col); 


тут тоже все очевидно и просто
Аватар пользователя
mfcoder
 
Сообщений: 1538
Зарегистрирован: 29 июл 2013, 11:55
Средств на руках: 26.85 Доллар
Группа: Базовая
Благодарил (а): 78 раз.
Поблагодарили: 423 раз.

Re: Философия MQL4

Сообщение mfcoder » 14 сен 2013, 19:03

3.1.5.3. Создание трендовой линии

трендовая линия - это луч или отрезок построенные по двум парам координат цена/время, в случае если строится луч, то его направление определяется координатами, т.е. если правая координата времени меньше (дальше по истории), чем вторая, то направление луча направо от первой координаты, иначе в обратную сторону, ну и конечно же, можно построить и горизонтальную и вертикальную трендовую..

пример создания линии
Код: выделить все
string name = "трендовая линия";
int window = 0, time1 = Time[10], time2 = Time[0];
double price1 = High[10], price2 = Low[0];
color col = Green;

ObjectCreate(name, OBJ_TREND, window, time1, price1, time2, price2);
ObjectSet(name, OBJPROP_COLOR, col);   


в данном случае будет нарисован луч, т.к. по умолчанию рисуется луч, с началом на 10-м баре и в направлении к 0-му бару и за него..

чтобы вместо луча рисовался отрезок с 10 по 0-й бары нужно выставить свойству "луч" значение false, т.е. нужно добавить такой вызов
Код: выделить все
ObjectSet(name, OBJPROP_RAY, false);


тогда вместо луча получим отрезок от цены (High) одного бара к цене (Low) другого
Аватар пользователя
mfcoder
 
Сообщений: 1538
Зарегистрирован: 29 июл 2013, 11:55
Средств на руках: 26.85 Доллар
Группа: Базовая
Благодарил (а): 78 раз.
Поблагодарили: 423 раз.


Вернуться в MQL – теория и практика

Кто сейчас на форуме?

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 26

Права доступа к форуму

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения