Перейти к содержанию
Форекс Форум трейдеров Академии «MasterForex-V»

Основы языка MQL


Рекомендуемые сообщения

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

 

Для чего надо знать язык скриптов? Ведь самих скриптов уже огромная куча..... :)

Прежде всего для вас самих. Все скрипты были написаны кем-то для себя и не всегда вывод может вас удовлетворить. Во-вторых, может и не быть того скрипта, который вам подойдёт и вам захочется его сделать... В общем, знание языка никогда не мешало!

 

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

Ссылка на комментарий
Поделиться на другие сайты

MetaQuotes Language

Введение

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

 

1. Структура программы

Все модули должны иметь определённую структуру:

  • команды препроцессора
    Здесь указываются все команды препроцессора, описание индикаторов и объявление именованых констант
  • объявления переменных
    Здесь объявляются и (если надо) инициализируются переменные
  • объявления функций
    Здесь объявляются и описываются все функции, которые будут использованы в модуле
  • функция init()
    Эта функция всегда автоматически вызывается при начальной инициализации модуля. При необходимости её можно вызвать из любого места модуля.
  • функция deinit()
    Эта функция вызывается при деинициализации (удаление модуля из памяти). Применяется для удаление объектов, которые были созданы этим модулем и которые уже не нужны.
  • функция start()
    Это главная функция. Она имеет некоторые особенности:
    1. при её отсутствии модуль (скрипт, индикатор или советник) не работает.
    2. она вызывается всегда после функции init().
    3. для индикаторов - вызывается всегда, когда окно, к которому прикреплён этот индикатор становится активным.
    4. для индикаторов и советников - вызывается после прихода очередного тика. В случае, если функция не отработала полностью, следующий тик может быть не отработан.

Все это мы будем изучать более подробно.

Ссылка на комментарий
Поделиться на другие сайты

2. Команды препроцессора

  • #define - объявление именованых констант.
    Эта конструкция может использоваться в любом месте модуля. Важно чтобы объявление было до использования константы, в противном случае будет ошибка компилляции.
    К именам констант применяются такие же требования как и к именам переменных (будет далее). Чаще всего имена констант делают ЗАГЛАВНЫМИ буквами. Таким образом они всегда выделяются в теле модуля Но это не обязательно.
    Пример:
    MQL
    #define МояКонстанта 2

    Здесь определяется целое число 2 как МояКонстанта. При компилляции модуля везде константа МояКонстанта будет заменена на число 2.
  • #property - специальные параметры скрипта/индикатора/советника
    Их много и им будет посвящён отдельный пост.
  • #include - команда включения файла в текст модуля.
    Команда может встречаться в любом месте программы, но обычно все включения размешаются в начале файла исходного текста. Очень удобно для модульного написания индикаторов/советников. После компилляции модуля присутствие включённого файла не нужно (он был включён в скомпиллированный модуль).
    MQL
    #include <MyHeaders.mqh>
    #include "MyHeaders.mqh"

    Если имя файла заключено в угловые скобки (<>), то этот файл должен находиться в стандартном каталоге experts\include. Если имя файла заключено в кавычки, то файл должен находиться в текущем каталоге.
  • #import - импорт исполняемых файлов.
    Эта команда позволяет полностью использовать вычислительные возможности компьютера. С помощью этой команды включаются скомпиллированные модули EX4 и системные библиотеки DLL. Более подробно и с примерами мы разберём в дальнейшем.

Изменено пользователем Liv
Ссылка на комментарий
Поделиться на другие сайты

#property - специальные параметры скрипта/индикатора/советника

Специальные параметры используются для:

  1. выделения памяти и определения линий
  2. настройки отображения индикаторов
  3. определения общего вида вывода

Рассмотрим подробно каждый из параметров:

 

link

Cсылка на сайт производителя. Значение - строчная константа.

copyright

Название компании-производителя. Значение - строчная константа.

stacksize

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

library

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

indicator_chart_window

Указывает, что нужно выводить индикатор в окно графика.

indicator_separate_window

Указывает, что нужно выводить индикатор в отдельное окно.

indicator_buffers

Определяет количество буферов (массивов) для расчета индикатора. Целое число от 1 до 9.

indicator_minimum

При определении отдельного окна, указывает на нижнее, минимальное ограничение шкалы окна индикатора. Тип числа double. Значение может быть как отрицательным, так и положительным.

indicator_maximum

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

indicator_colorN

Определяет цвет для вывода линии индикатора. N - целое число от 1 до 9 указывает на конкретную линию индикатора. Значение типа color (см. описание ниже).

indicator_widthN

Определяет толщину линии индикатора N, где N от 1 до 8. Значение - целое число указывающее на количество пикселей в линии

indicator_styleN

Определяет стиль линии индикатора N, где N от 1 до 8. Значение - целое число, уазывающее тип линии. В MQL определены константы, которыми просто пользоваться:
  • STYLE_SOLID
    - сплошная линия

  • STYLE_DASH
    - штриховая линия

  • STYLE_DOT
    - пунктирная линия

  • STYLE_DASHDOT
    - штрих-пунктирная линия

  • STYLE_DASHDOTDOT
    - штрих-пунктирная линия с двойными точками

indicator_levelN

Определяет наличие горизонтальный линии-уровня N в отдельном окне индикатора, где N от 1 до 8. Удобно для визуального анализа сделать несколько горизонтальных линий. Значение типа double, может быть как положительным, так и отрицательным.

indicator_levelcolor

Определяет цвет горизонтальных линий-уровней индикатора в отдельном окне. Тип - color.

indicator_levelwidth

Определяет толщину горизонтальных линий-уровней индикатора. Значение - целое число в пикселях.

indicator_levelstyle

Определяет стиль горизонтальных линий-уровней индикатора. Тип - целое число. Можно использовать константы типа линий как у indicator_style.

show_confirm

Устанавливает нужно ли выводить окно подтверждения перед запуском скрипта. Используется только в пользовательских скриптах; в индикаторах и советниках игнорируется.

show_inputs

Устанавливает нужно ли выводить окно со свойствами перед запуском скрипта и запретить вывод окна подтверждения, т.е. если указан этот параметр, то параметр show_confirm игнорируется.

Примеры:

MQL
#property link "http://forex.orotukan.ru/"

#property copyright "Мои собственные права :)."

#property library // это будет библиотека

#property stacksize 1024 // ну очень глубокая рекурсия! :)

 

#property indicator_chart_window // эти два параметра противоречат друг другу

#property indicator_separate_window // и будет работать тот, который объявлен последним

#property indicator_buffers 1 // будет 1 линия

#property indicator_minimum 0 // линия будет бегать от 0

#property indicator_maximum 100 // до 100

#property indicator_color1 RED // линия будет красной

#property indicator_width1 1 // толщина будет 1 пиксель потому, что будет пунктир

#property indicator_style1 STYLE_DOT // укажем её пунктирной

#property indicator_level1 50 // а по средине окна будет проведена тонкая линия

#property indicator_levelcolor SILVER // она будет серебристая (светло-серая)

#property indicator_levelwidth 1 // толщина 1 пиксель

#property indicator_levelstyle STYLE_DOT // пунктирная

 

#property show_confirm // это для скриптов - подтверждение запуска скрипта.

#property show_inputs // или запрос ввода параметров

Изменено пользователем Liv
Ссылка на комментарий
Поделиться на другие сайты

3. Объявления переменных

Каждая переменная, перед использованием должная быть объявлена и назначена. В MQL эти два процесса можно объеденить в одну операцию.

Например:

MQL
int igTFrame = Period();

Здесь объявляется целая (int) переменная igTFrame, которая будет содержать в себе текущий таймфрэйм.

Указание типа перед переменной обязательно, потому, что в данном случае идёт виделение памяти для этой переменной. Существует несколько типов:

  • int - целые числа... это числа без дробей в промежутке от -2147483648 до +2147483647.
  • double - числа двойной точности с плавающей точкой. В общем-то, значение этого числа трудно даже представить.... что-то там в степени 308!... а точность обеспечивается 15 значащами цифрами. Хватит на многое. :smile:
  • bool - логические значения true и false; ну, с этим, думаю всё понятно - всего два значения - истина и ложь.
  • string - символьные строки;
  • color - целое число, представляющее RGB-цвет; достаточно простое значение переменной, представить можно в нескольких типах:
    • литералы; тем, кто привык работать с палитрами, это представление цвета будет наиболее удобным:
      C'128,128,128' // серый
      C'0x00,0x00,0xFF' // синий
    • названия цветов - этим пользоваться проще всего:
      Red // красный
      Yellow // желтый
      Black // черный
    • целочисленные представления
      0xFFFFFF // белый
      16777215 // белый
      0x008000 // зеленый
      32768 // зеленый

    [*]datetime - дата и время, беззнаковое целое число, содержащее количество секунд, прошедших с 0 часов 1 января 1970 года. Для представления в удобочитаемый вид существует множество функций, которые мы будем использовать в своих занятиях.

Имена переменных составляются из букв, цифр и знака подчёркивания "_", не должны начинаться на цифру. В руководствах указывается, что переменные должны нести буквы латинского алфавита, но после многочисленных проверок, я удостоверился, что можно называть по-русски и переменные, и константы, и пользовательские функции. Длина переменной (константы, функции) не должная превышать 31 символ. Регистр различается, т.е. МояПеременная и мояПеременная - это разные переменные! Имеется ряд зарезервированных слов, кот. нельзя использовать в качестве переменной (константы, функции). Здесь я их перечислять не буду, их не много. При попытке использовать это слово в другом качестве появится ошибка при компилляции модуля.

Ссылка на комментарий
Поделиться на другие сайты

Переменные (продолжение)

Область видимости

Все переменные имеют область видимости. Этот термин означает, что переменная где-то видна, а где-то может быть не видна. К сожалению, в языке MQL нет специальных инструкций для определения области видимости переменных (глобальная, локальная, частная и пр.). Но тут всё просто!

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

Примеры:

MQL
/*

 Здесь объявлена переменная Proba.

 Она является глобальной, т.к. объявлена в начале модуля, вне функций и

 внешней, т.е. редактируемой пользователем.

*/

extern int Proba=1;

 

/*

 назначаем глобальную переменную Proba1

 она объявлена в начале модуля и будет видна

 во всех функциях

*/

int Proba1=2;

 

/*

 В этой функции тоже объявим локальную переменную Proba1

 ошибки никакой не будет, но компиллятор предупредит,

 что произошло повторное объявление переменной Proba1,

 т.к. была объявлена глобальная переменная Proba1

 И тут же объявлена локальная переменная Proba2.

*/

void test1() {

 int Proba1=4;

 int Proba2=0;

 Print("Proba1=" ,Proba1); // выведется "Proba1=4"

 Print("Proba2=" ,Proba2); // выведется "Proba2=0"

}

 

/*

 А в этой функции просто выводятся значения переменных.

 Proba1 выведется нормально, но при выводе

 переменной Proba2 произойдёт ошибка

*/

void test2() {

 Print("Proba1=" ,Proba1); // выведется "Proba1=2"

 Print("Proba2=" ,Proba2); // будет ошибка! Переменная Proba2 не будет найдена!

}

Есть очень интересная инструкция static. Она предназначена для локальных переменных (для глобальных - не имеет никакого значения). При указании переменной как static, её значение сохраняется до следующего вызова функции.

Пример:

MQL
int test() {

 static int proba;

 proba = proba+1;

 return(proba);

}

 

int start() {

 int proba1=0;

 for(int i=0;i<=10;i++){

proba1=test();

Print(proba1,"," );

 }

 return(0);

}

В результате выполения этого скрипта будет выведен через запятую ряд цифр от 1 до 10.

 

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

 

И, наконец, есть ряд переменных, о которых стоит сказать особо: массивы.

Ссылка на комментарий
Поделиться на другие сайты

Массивы

Массивы - это проиндексированная совокупность однотипных данных.

К примеру, у нас есть данные по цене (свеча):

High = 1.3447

Open = 1.3431

Close = 1.3437

Low = 1.3430

Эти данные можно занести в массив:

MQL
double ОднаСвеча[]={1.3447,1.3431,1.3437,1.3430};

В итоге все данные сгруппированы в одном одномерном массиве, где High будет находиться под индексом 1, Open - 2, Close - 3, Low - 4.

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

MQL
double Свечи[24][4]; // объявляем массив 24х4

for(int i=24;i>0;i--){

 for(int j=1;j<=4;j++){

if (j==1) Свечи[j]=iHigh(NULL,PERIOD_H1,i);

else if (j==2) Свечи[j]=iOpen(NULL,PERIOD_H1,i);

else if (j==3) Свечи[j]=iClose(NULL,PERIOD_H1,i);

else if (j==4) Свечи[j]=iLow(NULL,PERIOD_H1,i);

 }

}

После этого, получить цену открытия, например, в 12 часов можно очень легко:

MQL
double ЦенаОткрытия12 = Свечи[12][2];

 

Но главное использование массивов в языке MQL - это индикаторы. Вывод графика на экран проводится с помощью связанного массива. Но об этом см. ниже.

Ссылка на комментарий
Поделиться на другие сайты

Предопределенные переменные

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

  • Ask
    Текущая цена продажи, ask - по-английски - спрашивать, просить... соответственно здесь - это цена спроса.
  • Bars
    Количество баров на текущем графике. Зависит от закаченой истории.
  • Bid
    Текущая цена покупки. Bid - по-английски - приказывать, предлагать цену - это цена предложения.
  • Close
    Это массив, в котором проиндексированы по барам цены закрытия каждого бара текущего графика. Индекс начинается с 0 и заканчивается числом баров текущего графика (Bars-1), т.е. цена закрытия текущего бара будет Close[0].
  • Digits
    Количество цифр после запятой в ценах. Зависит от используемого инструмента, т.е. если на EURUSD Digits будет равна 4, то на USDJPY - 2.
  • High
    Это массив, в котором проиндексированы по барам максимальные цены каждого бара текущего графика. Индекс начинается с 0 и заканчивается числом баров текущего графика (Bars-1), т.е. максимальная цена текущего бара будет High[0].
  • Low
    Это массив, в котором проиндексированы по барам минимальные цены каждого бара текущего графика. Индекс начинается с 0 и заканчивается числом баров текущего графика (Bars-1), т.е. минимальная цена текущего бара будет Low[0].
  • Open
    Это массив, в котором проиндексированы по барам цены открытия каждого бара текущего графика. Индекс начинается с 0 и заканчивается числом баров текущего графика (Bars-1), т.е. цена открытия текущего бара будет Open[0].
  • Point
    Размер одного пункта ("pip") в текущем инструменте.
  • Time
    Массив, содержащий время открытия каждого бара текущего графика. Данные представляют собой тип datetime и напрямую использовать не очень-то и понятно. Но имеется достаточно много функций преобразования этого числа в удобочитаемую форму.
  • Volume
    Массив, содержащий количество тиков каждого бара текущего графика.

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

Ссылка на комментарий
Поделиться на другие сайты

4. Объявления функций

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

Функции можно разделить на несколько категорий:

  • общие функции
  • преобразования типов
  • даты и времени
  • информация о счёте
  • обработка массивов
  • проверка состояния
  • файловые
  • математические
  • строковые
  • графические
  • пользовательские индикаторы
  • технические индикаторы
  • доступ к таймсериям
  • торговые функции
  • операции с графиками
  • пользовательские функции
  • специальные функции init(), deinit(), start()

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

При создании пользовательской функции, вам необходимо помнить следующее:

  1. положение об имени функции такое же самое как и у имени переменной (см. выше)
  2. функция должная иметь тип так же, как и переменная.
  3. если функция ничего не должна возвращать (аналог процедуры), то ей присваивается тип void
  4. все переменные объявленные внутри функции будут локальными и будут видны только внутри этой функции.
  5. все параметры, обявленные при объявлении функции и переданные ей - будут локальными и, соответственно, будут видны только внутри этой функции за исключением передачи параметра по ссылке (об этом позднее).
  6. не назначенные параметры передавать в функцию обязательно (позднее мы поговорим об этом).

Пример:

MQL
bool ПроверкаНаличия(int Что_то=0) {

 bool ret=false;

 if (Что_то==1) ret=true;

 return(ret);

}

Здесь объявлена пользовательская функция логического типа (bool) ПроверкаНаличия. В качестве параметра в неё передается целое значение (int), но необязательно, ибо при объявлении параметра происходит назначение по-умолчанию, т.е. если в функцию передали значение, например так:

MQL
bool Вопрос = ПроверкаНаличия(1);

то это значение присваивается переменной Что_то.

Если ничего не передаётся:

MQL
bool Вопрос = ПроверкаНаличия();

то переменной Что_то присваивается значение по-умолчанию - 0.

 

Из всех категорий функций, перечисленных мной выше, функция start() является обязательной во всех модулях, кроме библиотек. Созданием библиотек мы займёмся на практических занятиях позднее.

 

При загрузке (первого обращения) скомпиллированного модуля в память и работу происходит следующее:

  1. происходит выделение памяти под объявленные переменные
  2. присваивание переменным значений, в т.ч. и посредством заголовочного окна, где вам предлагается изменить значания
  3. определение всех функций
  4. выполнение функции init()
  5. выполнение функции start()

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

 

При запуске индикатора или советника, после инициализации модуль ждёт следующего тика и при каждом тике выполняется функция start(). После завершения работы (удаление индикатора или советник) выполняется функция deinit(). Функции init() и deinit() являются не обязательными. Например, для скрипта они вообще не нужны и там всё будет исполняться в функции start().

 

Библиотека служит просто хранилищем объявлений констант, переменных и функций и сама никакой работы не выполняет.

 

Я описал это для того, чтобы вы представляли себе структуру модуля и очёдность исполнения.

 

На этом краткий теоретический курс мы закончим и приступим к практическим занятиям.

Изменено пользователем Liv
Ссылка на комментарий
Поделиться на другие сайты

Гость
Эта тема закрыта для публикации ответов.
×
×
  • Создать...