Jump to content
Programmer

Курс MQL4

Recommended Posts

Programmer

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

 

Курс совмещает в себе глубокую теоретическую основу и практические занятия. Новичкам он будет полезен при формировании фундаментальной базы знаний как по MQL4, так и по основным концепциям программирования в целом. Матёрым программистам ;) данный курс поможет систематизировать свои знания.

 

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

 

Просьба все вопросы и замечания высказывать в теме "Общие вопросы".

Share this post


Link to post
Share on other sites
Programmer

УРОК 1



 

Если Вы умеете программировать на C или C++, то Вы уже очень многое знаете про MQL4. Если Вы не изучали никакого языка программирования, то никаких проблем в этом нет - я заодно научу Вас понимать концепцию программирования.

Итак, начнём с самого начала.

 

MQL4? Что, где и почему?

 

MQL4 обозначает MetaQuotes Language 4.

MetaQoutes - это компания, которая создала торгговую платформу MetaTrader.

Для того, чтобы сделать эту торговую платформу сильней платформ своих конкурентов, компания MetaQuotes снабдила её встроенным языком программирования, которые позволяют пользователю (Вам) реализовывать свои торговые стратегии.

Этот язык позволяет Вам создавать следующее:

 

1-Советники

2-Индикаторы

 

3-Скрипты

  • Советник - это программа, которая может автоматизировать Ваши сделки. Например, она может автоматизировать открытие Ваших сделок, закрывать их, отменять/заменять сделки.
  • Индикатор - это программа, которая позволяет Вам пользоваться функциями технических индикаторов, но не может автоматизировать Ваши сделки.
  • Скрипт - Это программа, выполняющая одну функцию. В отличии от советников, скрипты исполняются однократно - при востребовании, а не на каждом тике. И, конечно же, скрипт не имеет доступа к техническим индикаторам.



Это были ответы на вопросы: "Что" такое MQL4? "Почему" надо использовать MQL4?

Теперь, "Где" писать MQL4?

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

 

1-Сложный путь:

 

Сложный путь заключается в использовании Вашего любимого текстового редактора и команды prompt для компиляции.

Блокнот - неплохой выбор, но не забывайте две вещи:

 

1-сохранять файл, который Вы создали в обычном текстовом формате.

2-сохранять файл с расширением .mq4 (это чтобы потом было легче

открыть его с помощью MetaEditor), хотя можете сохранять в любом формате.

 

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

Это шаг компиляции.

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

MetaTrader снабжён своим собственным компилятором (программа, которая превращает Ваш код в машинный язык), называемым MetaLang.exe.

MetaLang.exe - консольная программа, которая на входе берёт два параметра, а на выходе даёт файл формата .ex4 (такие файлы понимает метатрейдер).

Первый параметр - это опции, и единственная возможная опция - это -q (quit)

Второй параметр - полный путь к Вашему .mql файлу.

 

Синтаксис выглядит так:

metalang [options...] filename

 

Пример:

 

1- найдите путь к своему metalang.exe, он лежит там же, где и MetaTrader (например: D:\Program Files\MetaTrader 4)

 

2- создайте batch-файл и назовите его compile.bat (или любым другим именем)

 

3- напишите следующие строки в bat-файл, а затем сохраните его:

cd D:\Program Files\MetaTrader 4

metalang -q "D:\ProgramFiles\MetaTrader 4\my_first_script.mq4"

(не забудьте подставить свой путь к MetaTrader)

 

4- Запустите batch-файл, и если Вам повезёт, то Вы увидите:

 



Рис. 1

 

Как видите, у Вас появился файл "my_first_mql4_script.ex4"

 

2-Простой путь

 

В MetaTrader есть хороший встроенный редактор, называемый MetaEditor, который имеет три особенности:

 

1- Он подчёркивает различные конструкци языка MQL4, пока вы читаете/набираете код.

 

2- Очень легко компилировать программы. Надо просто нажать F5, и MetaEditor сам сделает всю сложную работу и создаст файл .ex4.

К тому же, очень легко понять, что не так в Вашей программе, взглянув в инструментарий. (см. рис. 2)

 

3- Встроенный исчерпывающий словарь.

 



рис. 2

 

В следующих уроках нам предстоит узнать больше о MetaEditor.

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

 

© Kirill. [email protected]

post-50854-1404214279,2706_thumb.png

post-50854-1404214279,3145_thumb.gif

post-50854-1404214279,3671_thumb.gif

Edited by Programmer

Share this post


Link to post
Share on other sites
Programmer

Урок 2 - СИНТАКСИС

 

Всем привет.

Сегодня мы разговариваем про синтаксис языка MQL4.

И, как я уже говорил, если Вы программируете на C или C++, то Вы уже очень многое знаете про MQL4.

Это потому, что синтаксис MQL4 очень похож на синтаксис C.

 

Синтаксис — сторона языка программирования, которая описывает структуру программ как наборов символов (обычно говорят — безотносительно к содержанию). "Wikipedia"

 

Т.е. когда мы изучаем синтаксис языка, мы изучаем его грамматику и правила написания, которые состоят из:

 

 

 

  • Форматирование
  • Комментарии
  • Идентификаторы
  • Зарезервированные слова

Разберёмся с каждым из этих пунктов отдельно.

 

1 - Форматирование текста

 

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

Например, следующие коды равнозначны в MQL4:

double  MacdCurrent, MacdPrevious, SignalCurrent;

double  
MacdCurrent,
MacdPrevious, 
SignalCurrent;

double        MacdCurrent,      MacdPrevious,    SignalCurrent;

Но, как Вы видите, первый вариант более читаем и проще воспринимается.

Однако, к любому правилу есть исключения:

 

1. Запрещено исрользовать символ переноса строки после знака решётки:

Например, следующая строка неверна:

#property 
copyright "Copyright © 2004, MetaQuotes Software Corp."

А эта верна:

#property copyright "Copyright © 2004, MetaQuotes Software Corp."

2. Запрещено использовать пробельные символы внутри констант, идентификаторов и ключевых слов.

Например, следующая строка верна:

extern int MA_Period=13;

Здесь "extern" и "int" - ключевые слова, "MA_Period" - идентификатор, а "13" - константа.

Но об этом подробнее в следующем уроке.

Следующие строки неверны:

extern int MA_Period=1
3;

extern int MA_Period=1     3;

ex
tern int MA_Period=13;

2 - Комментарии

 

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

Вы пишите комментарии, которые компилятор игнорирует. Зато код становится понятней.

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

MQL4 (как и C/C++) и спользует два типа комментариев:

 

Однострочные комментарии

Однострочный комментарий начинается с символов // и заканчивается переходом на новую строку.

Например:

//Это комментарий
extern int MA_Period=13;

extern int MA_Period=13; //Это ещё один комментарий

Многострочные комментарии

Многострочные комментарии начинаются символами /* и заканчиваются символами */

Например:

/*Это
многострочный 
комментарий*/

Однострочные комментарии разрешается вкладывать внутрь многострочных:

/*Это
многострочный  //А это ещё один комментарий 
комментарий*/

Ещё пример:

extern int /*HELLO! I’m a comment*/ MA_Period=13;

А вот так нельзя:

extern int //test MA_Period=13;

Многострочные комментарии вкладывать друг в друга запрещается.

 

3. Идентификаторы

 

Идентификатор - это имя, которое Вы присвоили своей переменной, константе или функции.

Например:

extern int MA_Period=13;

Здесь MA_Period - идентификатор.

 

 

 

Есть несколько правил и ограничений в выборе идентификаторов:

  1. Длина идентификатора не должнеа превышать 31 символа.
  2. Идентификатор должен начинаться с буквы (большой или маленькой) или с символа _.
  3. В качестве идентификаторов нельзя использовать зарезервированные слова, с которыми мы скоро познакомимся.
  4. Идентификаторы чувствительны к регистру. Т.е. MA_Period и ma_Period - это разные идентификаторы.

Рассмотрим несколько примеров:

Name1     верно
_Name1      верно

1Name     неверно
~Name1      неверно
N~ame1      неверно
i_love_my_country_and_my_country_loves_all_the_world  
        неверно
Color       верно
color        неверно (зарезервированное слово)

4. Зарезервированные слова

 

Есть "слова", которые язык использует для определённых целей.

Их запрещается использовать в качестве идентификаторов или в любых других целях.

Список зарезервированных слов:

 

 

Например, следующие строчки кода неверны:

extern int datetime =13;
int extern =20;
double continue = 0;

© Kirill. [email protected]

post-50854-1404214279,4313_thumb.gif

Edited by Programmer

Share this post


Link to post
Share on other sites
Programmer

Урок 3 - Типы данных в MQL4

 

Что такое тип данных?

 

Любой язык программирования имеет свои названия для описания различных данных хранящихся в памяти.

Например, если в памяти хранится число от -2147483648 до 2147483647, в большинстве языков программирования оно будет называться "integer".

 

Переменные?

 

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

 

 

 

 

Чтобы было легче понимать, что происходит, представьте себе, что память - это набор коробок различных размеров. Размер коробки - это эквивалент количества бит, требуемого для хранения данного типа.

  • Чтобы использовать коробку для хранения данных, необходимо присвоить ей имя. Этот процесс называется объявлением.
  • В процессе объявления Вы используете слово, чтобы объяснить компьютеру какого размера коробка Вам нужна. Это слово называется ключевым.
  • Лучше дать имя коробке такое, чтобы потом было легко понять, что в ней лежит.
  • Данные кладутся в коробку путём присвоения данных коробке.
  • Если объявление и присвоение данных происходит в одной строчке, то такой процесс называется инициализацией.

Когда мы создаём переменную, мы говорим компьютеру, что мы хотим, чтобы он присвоил часть памяти определённого размера (в битах) нашей переменной. Поскольку хранение числа, буквы или большого числа занимает разный объём памяти, компьютер спросит, что Вы хотите хранить в этой памяти, и каков размер данных. Для этого и нужны типы данных.

Например, если мы дадим компьютеру следующую строчку кода:

int  MyVaraible=0;

то мы говорим компьютеру, что хотим, чтобы он выделил блок памяти длиной 4 байта под нащу переменную "MyVariable".

В этом примере:

 

int - это ключевоу слово

int - тип данных integer

int - объявление

MyVariable - имя переменной

=0 - инициализация

О переменных мы узнаем больше в следующих уроках.

 

 

 

 

 

В MQL4 присутствубт следующие типы данных:

  • Integer (int)
  • Boolean (bool)
  • Character (Char)
  • String (String)
  • Floating-point number (double)
  • Color (color)
  • Datetime (datetime)

1 - Integer

 

 

Integer - это число, которое может начинаться с + или - и состоит из цифр. Это число может лежать в пределах между -2147483648 и 2147483647.

MQL4 может представлять integer в десятичной или шестнадцатиричной системе.

Например, следующие числа - типа integer:

12, 3, 2134, 0, -230
0x0A, 0x12, 0X12, 0x2f, 0xA3, 0Xa3, 0X7C7

Ключевое слово int используется для создания переменной типа integet.

Например:

 

int intInteger = 0;
int intAnotherIntger = -100;
int intHexIntger=0x12;

2 - Boolean

 

Переменная типа Boolean может принимать лищь 2 значения: true или false (или их численные представления 1 и 0). И она занимает 1 бит (!) памяти.

В MQL4 true, TRUE, True равнозначны и false, FALSE, False - тоже.

Тип Boolean назван так в честь математика George Boole.

Ключевое слово bool используется для создания переменной типа Boolean.

Например:

 

bool I = true;
bool bFlag = 1;
bool bBool=FALSE;

3 - Character

 

Переменная типа Character - это один символ. Точнее,- это один из 256 алфавитных, циферных или специальных символов, заданных таблицой ASCII (American Standard Code for Information Interchange).

Символам присвоены числовые значения в соответствии с расположением в таблице.

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

'a' , '$' , 'Z'

Ключевое слово int используется для создания переменной типа Character.

Например:

 

int chrA = 'A';
int chrB = '$';

Некоторые символы, называемые Спец. Символами, не могут напрямую находиться внутри одинарных кавыч, потому что у них зарезервированные значения в языке MQL4.

В таких случаях мы используем escape-последовательности. Это означает, что мы ставим слэш-назад (\) перед символом.

Например:

int chrA = '\\';   //просто слэш
int chrB = '\n';   //символ новой строки

Список escape-последовательностей MQL4:

 

carriage return        \r
new line         \n
horizontal tab         \t
reverse slash        \\
single quote          \'
double quote         \"
hexadecimal ASCII-code    \xhh

4 - String

 

Переменная типа String - это набор символов, заключённых в двойные кавычки.

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

Символ NULL - это спец. символ (в таблице ASCII ему соответсвует число 0), используемый для обозначения конца строки.

На рис. 1 схематически изображено, как хранится в памяти строка "hello".



рис. 1 - Символы в массиве

MQL4 ограничивает размер строки 255 символами.

В строке можно использовать любые спец. символы, если перед ними Вы поставите \ .

Ключевое слово string используется для созания переменных типа String.

Например:

 

string str1 = "Hello world1, with you coders guru”;
string str2 = "Copyright © 2005, \"Forex-tsd forum\".";  //Notice the use of (") character.
string str3 = "1234567890";

5 - Floating-point number

 

Floating-point number - число с плавающей запятой - это действительное число.

Например: 3.0, -115.5, 15 и 0.0001.

Число такого типа может принимать значения от 2.2e-308 до 1.8e308.

Ключевое слово double используется для создания переменных типа Floating-point number.

Например:

 

double dblNumber1 = 1000000000000000;
double dblNumber3 = 1/4;
double dblNumber3 = 5.75;

6 - Color

 

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

Переменную типа Color можно задать тремя способами:

1 - Используя название цвета: Для часто используемых цветов (из набора Web-цветов) можно прямо присваивать переменной имя требуемого цвета.

2 - Используя символьное соответствие: Надо написать ключевой символ ( C ), и после него заключённые в одинарные кавычки (') должны идти координаты требуемого цвета в трёхмерном пространстве RGB (красный, зелёный, синий). Эти координаты должны быть в пределах от 0 до 255. Их можно задавать в десятичной или шестнадцатиричной системе.

3 - Используя числовое значение: Каждому цвету из набоора Web-цветов поставлен в соответствии свой код, который можно записывать как десятичной, так и в шестнадцатиричной системе. В шестнадцатиричной системе код записывается проще всего: 0xBBGGRR (BB - синий, GG - зелёный, RR - красный).

Например:

 

// символьное соответствие
C'128,128,128' // gray
C'0x00,0x00,0xFF' // blue
// название
Red
Yellow
Black
// числовое значение
0xFFFFFF    // white
16777215    // white
0x008000    // green
32768    // green

Ключевое слово color используется для создания переменной типа Color.

Например:

 

color clr1= Red;
color clr1= C'128,128,128';
color clr1=32768;

 

 

7 - Datetime

 

Тип данных Datetime - это специальный тип данных MQL4, который используется для хранения даты и времени. Чтобы задать значение переменной типа Datetime, надо написать ключевой символ (D), и после него заключённые в одинарные кавычки (') должна идти требуемая дата в формате год, месяц, день, час, минута, секунда. Переменные этого типа данных могут располагаться внутри временного диапазона от Jan 1, 1970 по Dec 31, 2037.

Например:

 

D'2008.01.01 00:00'  // Новый год
D'1980.07.19 12:30:27'
D'19.07.1980 12:30:27'
D'19.07.1980 12'  //равносильно: D'1980.07.19 12:00:00'
D'01.01.2004'   //равносильно: D'01.01.2004 00:00:00'

Ключевое слово datetime используется для создания переменной типа Datetime.

Например:

 

datetime dtMyBirthDay= D'1972.10.19 12:00:00'; 
datetime dt1= D'2005.10.22 04:30:00';

© Kirill. [email protected]

post-50854-1404214279,6731_thumb.gif

post-50854-1404214279,6979_thumb.jpg

Edited by Programmer

Share this post


Link to post
Share on other sites
Programmer

Урок 4 - Операции и выражения в MQL4

 

Что такое операции и выражения?

 

На самом деле Вы прекрасно знаете, что такое операции. Если я Вам скажу, что +,-,*,/ - элементарные арифметические операции, Вы очень быстро вспомните, что означает слово "операция".

Я уже слышу, как Вы говорите: "О! Так я же знаю, что такое операции, расскажи, что же такое тогда выражения?"

 

Идентификаторы (Вы их ещё помните? Если нет, то гляньте в урок СИНТАКСИС) совместно с Операциями образуют Выражения.

 

Запутались? Рассмотрим это на примере:

 

x = (y*z)/w

Здесь:

x,y,z и w - идентификаторы.

=,* и / - операции.

А вся строчка - это выражение.

Если в конце выражения поставить символ ";", то оно превращается в оператор:

 

x = (y*z)/w;

Комбинации выражений формируют оператор.

Комбинации операторов формируют функцию.

Комбнации функций формируют программу.

 

 

В оставшейся части урока мы будем говорить про типы операций в MQL4.

 

Начнём с элементарных математических операций:

 

1 - Арифметические операции

В MQL4 существует 9 арифметических операций:

 

 

 

Замечание: Нельзя комбинировать операция инкремента и декремента с другими выражениями.

Например, следующая строчка некорректна:

 

A=(B++)*5;

Но можно так:

 

A++;
B=A*5;

2 - Операции присваивания

Смысл любого выражения в формировании результата, а затем присваивания этого результата левому операнду.

Например:

 

A = B * C;

Здесь мы умножаем B на C и присваиваем результат A.

 

В MQL4 существует 11 операций присваивания:

 

 

 

 

3 - Операции сравнения

Операции сравнения сравнивают два значения (два операнда) и возвращают либо True, либо False.

Это как ответить на вопрос "Вася выше Саши ? Да/Нет ?"

Например:

 

4 == 4;   //true
4 < 4;     //false
4 <= 4   //true;

В MQL4 существует 6 операций сравнения:

 

 

 

 

4 - Логические операции

Логические операторы заимствованы из Булевой алгебры, которая суть манипулирование верностью концептуальных абстрактных высказываний, не вдаваясь в истинный смысл концепций. Значние верности в Булевой алгебре может принимать лишь два значения: верно или неверно (true OR false).

В MQL4 логические операции также называются Булевыми операциями.

 

В MQL4 используются три основных логических операции:

 

 

 

Замечание: Логические операции выполняются слева направо. Поэтому, если в операторе A && B; левый операнд равен нулю, то правый операнд даже не рассматривается. Аналогично, если в операторе A || B; левый оператор не равен нулю, то правый операнд даже не рассматривается.

 

 

5 - Битовые операции

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

В MQL4 доступны следующие битовые операции:

 

18497504ok1.gif

 

Замечание: Оба операнда, учавствующих в побитовых операциях, должны быть типа int.

 

 

6 - Другие операции

 

Есть несколько операций в MQL4, которые не входят ни в одну из предыдущих категорий:

  • Операция индексирования массива []
  • Операция вызова функции ()
  • Операция разделения аргументов функций , (запятая)

Мы подробнее узнаем про массивы и функции в следующем уроке. Так что просто запомните эти операции, как "Другие операции".

 

 

Приоритеты операций. Моё любимое ;)

 

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

 

x + y / 100
x + (y / 100) //недвусмысленно, рекомендую писать так

Используя составные операторы необходимо быть точным и указывать порядок выполнения операций явно с помощью скобок (). Такая практика сделает Ваш код более лёгким для прочтения и редактирования. *

 

Далее следует список операций. Чем выше операция в списке, тем выше её приоритет. Операции с более высоки приоритетом выполняются раньше операций с более низким приоритетом. Если выбор стоит между двумя одинаковыми операциями, то следует помнить, что все бинарные операции (те, в которых учавствуют два операнда) выполняются слева направо, а все операции присваивания - наоборот - справа налево.

Оставляю список на английском. Заодно будете знать, как называются операции на 'родном' языке ;)

 

() Function call From left to right

[] Array element selection

! Negation From left to right

~ Bitwise negation

- Sign changing operation

* Multiplication From left to right

/ Division

% Module division

+ Addition From left to right

- Subtraction

<< Left shift From left to right

>> Right shift

< Less than From left to right

<= Less than or equals

> Greater than

>= Greater than or equals

== Equals From left to right

!= Not equal

& Bitwise AND operation From left to right

^ Bitwise exclusive OR From left to right

&& Logical AND From left to right

|| Logical OR From left to right

= Assignment From right to left

+= Assignment addition

-= Assignment subtraction

*= Assignment multiplication

/= Assignment division

%= Assignment module

>>= Assignment right shift

<<= Assignment left shift

&= Assignment bitwise AND

|= Assignment bitwise OR

^= Assignment exclusive OR

, Comma From left to right

 

* А теперь немного развлечения.

Обожаю приоритеты, потому что их почти никто никога наизусть не помнит. Достаточно выучить парочку и ты уже царь среди равных тебе программистов.

Например, можно спросить результат такого оператора ++ i ++; (но это уже больше к C/C++, где есть правый и левый инкремент). Или такого: i +++ i;

А вообще, приоритеты - один из хороших козырей в IOCCC - International Obfuscated C Code Contest — «международный конкурс запутанного кода на Си».

http://en.wikipedia.org/wiki/International..._C_Code_Contest[/url] - на это стоит посмотреть. Всегда улыбаюсь.

 

 

© Kirill. [email protected]

post-50854-1404214280,0221_thumb.jpg

post-50854-1404214280,0919_thumb.jpg

post-50854-1404214280,1239_thumb.jpg

post-50854-1404214280,1451_thumb.jpg

Edited by Programmer

Share this post


Link to post
Share on other sites
Programmer

Урок 5 - Циклы и Условия (часть 1)

 

Добро пожаловать на пятый урок моего курса по MQL4.

Программа, которую Вы пишите на MQL4 (или на любых других языках) выполняется сверху вниз (я имею ввиду откомплированный файл). Оператор за оператором.

Оператор - это строчка кода, которая говорит компьютеру что-либо сделать.

Например:

 

Print("Hello World");
return 0;

Точка с запятой является очень важной частью оператора, но обычно очень легко забывается, потому является причиной 90% всех ощибок.

 

Принцип выполнение кода сверху вниз имеет исключения - это циклы и условия.

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

Операторы, которые вызывают такие прыжки называются Операторами Контроля (контроллерами).

Контроллеры состоят из циклов и условий.

 

 

Циклы

Циклы заставляют раздел программы выполнятся определённое число раз.

Такое повторение продолжается пока какое-то условие явлется истинным (true) и прекращается как только условие становится ложным (false).

Когда цикл завершается контроль переходит следующему за циклом оператору.

В MQL4 существует два вида циклов:

 

1 - цикл for

Цикл for считается самым простым циклом, поскольку все его параметры собраны в одном месте.

Цикл for выполняет определённый раздел кода фиксированное число раз.

Например:

 

int j;
for(j=0; j<15; j++)
  Print(j);

Как это работает?

Оператор состоит из ключевого слова for, за этим следуют круглые скобки, в которых указаны 3 выражения, разделённые точками с запятыми:

 

for(j=0; j<15; j++)

 

Эти три выражения - это: выражение инициализации, выражение проверки и выражение инкремента.

j = 0 - выражение инициализации

j < 15 - выражение проверки

j++ - выражение инкремента

 

Тело цикла - это код, который будет выполняться:

Print(j); - тело цикла.

В нашем примере тело цикла выполняется 15 раз.

 

Замечание: сразу после выражения for(...;...;...) точка с запятой НЕ ставится, т.к. это выражение + идущее после него тело цикла считаются единым оператором.

 

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

 

Выражение инициализации

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

Вы можете объявить переменную цикла вне самого цикла, как в нашем примере:

 

int j;
for(j=0; j<15; j++)

Или Вы можете объявить её прямо внутри скобок цикла:

 

for(int j=0; j<15; j++)

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

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

 

int i;
int j;
for(i=0 ,j=0;i<15;i++)
  Print(i);

Выражение проверки

Выражение проверки - это выражение, которое построено на операциях сравнения и логических операциях (см. пред. урок).

Проверка истинности выражения происходит после каждого прохождения цикла. Цикл продолжается, если выражение истинно, цикл завершается, если выражение ложно.

В нашем примере тело цикла будет продолжать печатать i ( Print(i); ), пока условие j<15 верно. j пробежит значения 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14, затем j станет = 15 и цикл остановится. Контроль перейдёт оператору, следующему за циклом.

 

Выражение инкремента

Выражение инкремента только так называется. Его задача - изменять переменную цикла. В нашем случае оно увеличивает j на 1.

Например, в следующем примере распечатаются числа 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1:

 

int i;
for(i=15;i>0,i<;i--)
  Print(i);

Выражение инкремента выполняется самым последним в списке шагов цикла.

 

 



Схема 1. Цикл for.

 

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

 

int i;
int j;
for(i=0 ,j=0;i<15,i<;i++,j++)
  Print(i);

Но выражение проверки может быть только одно.

 

Тело цикла

Во всех предыдущих примерах в качестве тела цикла мы использовали толко один оператор. В большенстве случаев этого недостаточно.

В тело цикла можно записывать много операторов, если их все взять в фигурные скобки:

 

for(int i=1;i<=15;i++)
{
  Print(i);
  PlaySound("alert.wav");
}

В этом коде в теле цикла содержится два оператора. Программа будет выполнять 1й оператор, а за ним 2й при каждом прохождении цикла.

Не забывайте ставить точку с запятой в конце каждого оператора.

 

Оператор Break

Если при выполнении цикла for (или цикла while, или оператора switch) встречается оператор break;, то цикл терминируется, а контроль переходит оператору, следующему за циклом. PS: break - это ключевое слово.

Например:

 

for(int i=0;i<15;i++)
{
 if((i==10)
break;
 Print(i);
}

В этом примере цикл будет нормально выполняться пока i не достигнет значения 10. Как только это произойдёт, оператор break; остановит цикл. В результате, на экран распечатаются: 0,1,2,3,4,5,6,7,8,9.

 

Оператор Continue

Оператор break; останавливает цикл, а оператор continue; переводит цикл на следующий шаг, игнорируя оставшиеся операторы тела цикла.

Например:

 

for(int i=0;i<15; i++)
{
  if(i==10) continue;
  Print(i)
}

В этом примере цикл будет нормально выполняться пока i не достигнет значения 10. Как только это произойдёт, оператор continue; переведёт цикл на следующий шаг, и i=10 НЕ распечатается. В результате, на экран распечатаются: 0,1,2,3,4,5,6,7,8,9,11,12,13,14.

 

Важно!

Часть или даже все управляющие выражения цикла for можно опускать.

Например:

 

for(;

Этот цикл равносилен циклу while, в котором выражение проверки всегда истинно.

Мы Вам представим цикл while прямо сейчас:

 

2 - цикл while

Цикл for обычно используется, когда Вы знаете, сколько раз цикл должен быть пройден. А что делать, если это не так?

Для этого есть цикл while.

В цикле while, как и в цыкле for есть выражение проверки, но в нём нет выражений инициализации и инкремента.

Пример:

 

int i=0;
while(i<15)
{
  Print(i);
  i++;




}

  • Переменная цикла была объявлена и проинициализирована ДО цикла. В отличии от цикла for, внутри скобок этого делать нельзя.
  • Формально i++ НЕ является выражением инкремента, но нам нужно чтобы что-то в цикле менялось, чтобы мы когда-нибудь из него выбрались.

Как же приведённый пример работает?

Оператор while содержит только выражение проверки, и он его проверяет после каждого прохождения цикла. Если оно истинно, цикл продолжится. Если оно ложно, цикл завершится и контроль перейдёт оператору, следующему за циклом.

В приведённом примере цикл будет выполняться пока i не станет равным 16. Как только это произойдёт, проверка условия i<15 вернёт false, и цикл завершится.

 

 



Схема 2. Цикл while.

 

Я уже говорил, что цикл while похож на цикл for. Вот их сходства:

1. В обоих можно использовать операторы break; и continue; .

2. В обоих тело цикла может быть одиночным или составным. Во вотром случае операторы тела цикла нужно брать в фигурные скобки.

3. Аналогом for(;;) является while(true).

 

 

© Kirill. [email protected]

post-50854-1404214280,219_thumb.png

post-50854-1404214280,2702_thumb.png

Edited by Programmer

Share this post


Link to post
Share on other sites
Programmer

Урок 6 - Циклы и Условия (часть 2)

 

Добро пожаловать на шестое занятие моего курса.

Надеюсь, что Вам понравились предыдущие уроки.

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

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

 

1 - Оператор if

Оператор if является самым простым среди операторов условия.

Пример:

 

if( x < 100 )
  Print("hi");

После if идут круглые скобки, в которых записывается выражение проверки (в данном случае x < 100). Если результат выражение проверки является истиной (true), то тело оператора if будет выполнено. В данном случае тело состоит из одного оператора - Print("hi"); . А если результат выажения проверки является ложью (false), то тело оператора if НЕ выполняется, а контроль переходит оператору, следующему за телом if.

 



Схема 1. Оператор if.

 

Несколько операторов в теле if

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

Пример:

 

if(current_price==stop_loss)
{
  Print("you have to close the order");
  PlaySound("warning.wav");
}

Обратите внимание на сумбол == и выражении проверки. Это одна из операций сравнения, которые Вы изучали в уроке 4 "Операции и Выражения".

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

 

Вложенные циклы и условия

Циклы и условия можно вкладывать друг в друга.

Пример:

 

for(int i=2; i<10; i++)
  if(i%2==0) 
  {
     Print("It's definetly not a prime number");
     PlaySound("warning.wav");
  }

Заметьте, что тело цикла в данном примере НЕ нужно заключать в фигурные скобки, потому что оператор if и все операторы внутри его тела считаются как один оператор.

 

2 - Оператор if ... else

Оператор if позволяет что-то сделать, если определённое условие выполняется. Допустим, мы хотим сделать что-то другое, если это условие не выполнено. Для этого есть оператор if ... else. Он состоит из оператора if и его тела, после чего идёт ключевое слово else и его тело.

Пример:

 

if(current_price>stop_loss) 
  Print("It’s not too late to stop, please stop!");
else
  Print("you're playing well today!");



Схема 2. Оператор if ... else.

 

Вложенные операторы if...else

Операторы if ... else и оператор if можно как угодно вкладывать друг в друга.

Пример:

 

if(current_price>stop_loss) 
  Print("It’s not too late to stop, please stop!");
if(current_price==stop_loss)
  Print("It’s time to stop!");
else
  Print("you're playing well today!");

Есть опастность, связанная с вложенными операторами if ... else. По невнимательности Вы можете случайно связать какой-то else не с тем if.

Чтобы избежать подобных ошибок, можно сделать одно из двух:

1 - всегда брать пары if ... else в фигурные скобки.

Вот так:

 

if(current_price>stop_loss) 
{
  Print("It’s not too late to stop, please stop!");
if(current_price==stop_loss)
  Print("It’s time to stop!");
else
  Print("you're playing well today!");
}

2 - Если Вам не подходит 1й вариант (слишком много этих if ... else, или Вам просто лень), то просто следуйте правилусвязывать else с ближайшим if.

 

3 - Оператор switch

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

Пример:

 

switch(x)
 {
  case 'A':
  Print("CASE A");
  break;
  case 'B':
  case 'C':
  Print("CASE B or C");
  break;
  default:
  Print("NOT A, B or C");
  break;
 }

После ключевого слова switch идут круглые скобки. Внутри этих скобок находится switch-константа. Внктри фигурных собок находятся case-константы - это проверямые условия switch-константы. Они записываются в виде case <значение>: <что делать>. <Значение> может быть integer, character или неизменным выражением.

Неизменность выражения означает, что оно не зависит от переменных. Например, выражение X+Y не является неизменным.

 

Как же работает указанный пример?

Оператор switch сравнивает switch-константу поочерёдно со всеми case-константами.

В случае x=='A' программа напечает "CASE A" и оператор break; прервёт оператор switch. Контроль передастся за пределы блока switch.

В случае x=='B' или x=='C', программа напечатает "CASE B or C". Это потому что нет оператора break; в case 'B': .

В случае x!= ни одной из case-констант, оператор switch выполнит блок default: и напечатает "NOT A, B jr C".

 



Схема 3. Оператор switch.

 

 

© Kirill. [email protected]

post-50854-1404214307,7285_thumb.png

post-50854-1404214307,7733_thumb.png

post-50854-1404214307,8296_thumb.png

Edited by Programmer

Share this post


Link to post
Share on other sites
Programmer

Урок 7 - Функции

 

Добро пожаловать в мир функций языка MQL4.

Работа с функциями в любом языке состоит из двух этапов:

- изучение функций, что, порой, очень скучное занятие

- использование функций, что всегда является спасательной шлюпкой.

Итак, начнём седьмой урок.

 

В чём смысл функций ?

Функция очень похожа на мясорубку - вы кладёте в неё мясо, лук, специи и получаете фарш.

Мясо, лук и специи называются параметрами функции (входными параметрами функции), фарш - возвращаемое значение. А механизм мясорубки - тело функции.

Есть только одно различие между функциями и Вашей мясорубкой: некоторые функции возвращают НИЧЕГО (в MQL4 ничего называется словом void).

Пример:

 

double          // тип фарша - возвращаемое значение
my_func (double a, double b, double c)  // название функции и список параметров (мясо, лук и специи)
 {         
  return (a*b + c);          // фарш на выход - функция возвращает некоторое значение
 }

 

Как Вы видите выше, функция начинается с типа возвращаемого значения "double", за ним следует имя функции, после которого идут круглые скобки.

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

В данном случае - три параметра: double a, double b, double c.

Затем идёт тело функции, которое заключено в фигурные скобки.

В данном примере, тело функции выполнит операцию (a*b + c).

Ключевое слово return ответственно за возвращение итого результата.

 

Ключевое слово return

Оператор return (); завершает работу функции (как break; завершает работу цикла), и передаёт контоль в точку вызова функции (об этом скоро).

Оператор return (); может содержать выражение в своих скобках, как в нашем примере. Это означает, что надо завершить работу функции и вернуть результат вычисление этого выражения.

Или оператор return (); может не содержать выражения в своих скобках. Тогда его единственная задача - завершить работу функции.

 

Внимание: не все функции используют оператор return (); Особенно, если возвращаемого значения нет, как в следующем примере:

 

void         // void означает, что фарша не будет – возвращаемое значение
my_func (string s) // function name and parameters list (meat & spices)
 {         
   Print(s);
 }

 

Эта функция не вернёт никакого значения, но она напечатает параметр s, который Вы ей предоставите. Чтобы показать, что функция ничего не возвращает, используется "void" в качестве её возвращаемого значения.

В некоторых языках программирования такие функции называются "методам", но в MQL4 они всё равно функции.

 

Вызов функции

Теперь, я надеюсь, мы понимаем, что такое функция. Как же использовать функции в Вашей программе?

Есть ещё один шаг, который нужно для этого сделать.

Этот шаг называется вызовом функции (её использованием).

Допустим, у Вас есть функция, котороая возвращает сумму двух integer.

Вот она:

 

int collect (int first_number, int second_number) 
 {         
   return(first_number+ second_number);
 }

 

Вы хотите ей воспользоваться в своей программе.

Делается это так:

int a = 10;
int b = 15;
int sum = [b]collect[/b](a,;
Print (sum);

В этом примере на экран распечатается 25. Магия! Но как компьютер узнал, что печатать?

Магической является строчка int sum = collect(a,B); Здесь Вы объявили переменную sum, чтобы в неё положить возвращаемое значение, а затем дали функции на вход два параметра (a,b).

Вы просто-напросто вызвали функцию.

Когда MQL4 видит имя функции в Вашей программе, он берёт Ваши параметры и идёт к функции, после чего он возвращается с результатом и кладёт его на то же место.

На самом деле, происходит следующее: в процессе компиляции MQL4 заменяет строчку с вызовом функции в вашей программе целиком телом самой функции (с учётом Ваших параметров). Причём вместо оператора return(); MQL4 производит присваивание возвращаемого им значения в родготовленную Вами переменную.

 

Вложение функций друг в друга

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

Пример:

 

void print_collection (int first_number, int second_number) 
 {         
   int sum = collect(first_number, second_number);
   Print(sum);
 }

 

В этом примере мы вызвали функцию collect внутри функции print_collection и распечатали результат. void означает, что возвращаемого значения нет (ещё помните?).

 

Спец. функции MQL4: init(), deinit(), start().

В MQL4 любая программа начинает своё выполнение с функции "init()" (initialize) и она срабатывает, когда Вы перетаскиваете программу (советника или индикатор) на график MetaTrader или если Вы поменяете валюту или период графика. Задача этой функции заключается в инициализации основных переменных, необходимых для работы Вашей программы. (Больще об инициализации переменных Вы узнаете в следующем уроке).

Когда Ваша программа заканчивает свою работу, или Вы закрываете окно графика, или меняете валюту или период графика, или закрываете терминал, срабатывает функция "deinit()" (de-initialize).

Третья функция (самая важная) "start()" срабатывает каждый раз, когда приходят новые котировки. 90% своей программистской жизни Вы проводите внутри этой функции.

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

 

 

© Kirill. [email protected]

  • Thanks 1

Share this post


Link to post
Share on other sites
Programmer

Урок 8 - Переменные в MQL4

 

Зачем нужны переменные?

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

 

 

 

Чтобы было легче понимать, что происходит, представьте себе, что память - это набор коробок различных размеров. Размер коробки - это эквивалент количества бит, требуемого для хранения данного типа.

  • Чтобы использовать коробку для хранения данных, необходимо присвоить ей имя. Этот процесс называется объявлением.
  • В процессе объявления Вы используете слово, чтобы объяснить компьютеру какого размера коробка Вам нужна. Это слово называется ключевым.
  • Лучше дать имя коробке такое, чтобы потом было легко понять, что в ней лежит.
  • Данные кладутся в коробку путём присвоения данных коробке.
  • Если объявление и присвоение данных происходит в одной строчке, то такой процесс называется инициализацией.

Когда мы создаём переменную, мы говорим компьютеру, что мы хотим, чтобы он присвоил часть памяти определённого размера (в битах) нашей переменной. Поскольку хранение числа, буквы или большого числа занимает разный объём памяти, компьютер спросит, что Вы хотите хранить в этой памяти, и каков размер данных. Для этого и нужны типы данных.

Например, если мы дадим компьютеру следующую строчку кода:

 

int  MyVaraible=0;

то мы говорим компьютеру, что хотим, чтобы он выделил блок памяти длиной 4 байта под нащу переменную "MyVariable".

 

В этом примере:

 

int - это ключевоу слово

int - тип данных integer

int - объявление

MyVariable - имя переменной

=0 - инициализация

 

О переменных мы узнаем больше в следующих уроках.

 

 

 

 

В MQL4 присутствубт следующие типы данных:

  • Integer (int)
  • Boolean (bool)
  • Character (Char)
  • String (String)
  • Floating-point number (double)
  • Color (color)
  • Datetime (datetime)

Я скопировал для Вас предыдущие строки из урока про типы данных. Теперь Вы вспомнили, что такое переменные - давайте посмотрим, как их надо объявлять:

 

Объявление:

Объявить переменную означает представить её миру и указать её тип. Для этого используются ключевые слова, которые мы прошли в уроке про типы данных (int, double, char, bool, string, color и datetime) и имя, которое Вы выбрали для своей переменной.

Например:

 

int  MyVaraible;

Здесь Вы объявили переменную под именем MyVariable, которая имеет тип integer. До строчки объявления 'слово' MyVariable в коде использовать нельзя. Если Вы попробуете это сделать, то компилятор MQL4 будет жаловаться и выдаст такую ощибку: 'MyVaraible' - variable not defined. 1 error(s), 0 warning(s).

 

Инициализация (присвоение)

Предупреждение: я писал, что инициализация - это присвоение значения переменной в строчке её объявления. Далее заменим слово "присвоение" словом "инициализация" для удобства.

Итак, инициализация означает присвоение значения переменной, например: MyVaraible=0; Инициализацию можно производить в той же строчке, что и объявление: int MyVariable=0;

А можно объявить переменную в одном месте, а инициализацию производить совершенно в другом:

 

int  MyVaraible;
…
…
MyVaraible=5;

Но помните, что объявление всегда идёт ДО инициализации.

 

Зоны видимости переменных

Есть два типа зон видимости переменной - локальная и глобальная.

 

1 - Локальная зона видимости

Локальные переменные не видны вне того мира, где они были объявлены. Границы 'мира' определяются ближайшей парой фигурных скобок {}. Сверху мир ограничен скобкой {, а снизу - скобкой }. Например, переменные, объявленные внутри функции, локальны для тела этой функции. Переменные, объявленные внутри цикла или услови локальны для этого цикла или условия, и они НЕ видны и НЕ могут быть использованы вне этого цикла или условия.

Например:

 

double my_func (double a, double b, double c) 
 {  
  int d;          
  return (a*b + c);
 }

В приведённом примере переменные a,b,c и d являются локальными и могут быть использованы только внутри тела этой функции.

 

2 - Глобальная зона видимости

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

Например:

 

int Global_Variable;
double my_func (double a, double b, double c) 
 {  
  return (a*b + c + Global_Variable);
 }

Здесь глобальная переменная Global_Variable объявлена вне функции (на уровне обявления функций), поэтому она видна всем функциям Вашей программы.

Глобальные переменные автоматически выставляются на нуль, если Вы их не проинициализировали при объявлении.

 

Внешние переменные

Ключевое слово "extern" используется для объявления переменных специального вида (не типа, а вида). Переменные такого вида используются для хранения входных данных программы, которые Вы можете ввести в окошке настроек Вашего советника или индикатора.

Например:

 

extern color Indicator_color = C'0x00,0x00,0xFF'; // blue
int init()
 {
  ...
 }

В этом примере переменная Indicator_color была объявлена, как extern, которую Вы увидите, когда прикрепите свой индикатор к графику в терминале, и которую можно менять в окошке настроек.

 

 



Рис. 1. Окошко настроек индикатора MA.

 

 

Здесь переменные Period, Shift, MA_method, Apply_to и Style - переменные, объявленные с использованием ключевого слова "extern". Поэтому они появляются в окошке настроек.

Если Вы хотите, чтобы пользователь мог изменять какую-либо переменную, сделайте её extern-переменной.

 

 

© Kirill. [email protected]

post-50854-1404214307,8586_thumb.jpg

Edited by Programmer

Share this post


Link to post
Share on other sites
Programmer

Урок 9 - Препроцессор

 

Что такое препроцессор?

Препроцессор - это программа, обеспечивающая предварительную обработку кода для его подготовки к компиляции.

Например, если Вы используете директиву #include <win32.h>, это означает, что Вы говорите препроцессору включить содержимое файла "win32.h" в том месте, где Вы написали ключевое слово include.

В MQL4 существуют 4 препроцессорные директивы:

 

1 - директива define

Директива define используется для задания значения константы. Константа очень похожа на переменную за тем исключением, что константе Вы придаёте значение только один раз и потом поменять его не можете.

Например:

 

#define my_constant    100

Как Вы можете заметить в приведённом примере нет символа присваивания "=", а есть только пробел между именем константы (my_constant) и её значением (100).

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

Имена констант подчиняются тем же правилам, что и имена переменных (урок 2 - Синтаксис), например нельзя начинать имя константы с цифры, и его длина не должна превышать 31 символ.

Значение константы может быть любым.

Препроцессор просто заменит Вашу константу на её значение везде, где повстречает её в коде. Да именно так - заменит одни символы (имя константы) на другие (её значение). И всё это произойдёт до компиляции, поэтому компилятор даже не заметит, что у Вас была какая-то константа.

Так что, Вашу константу можно применить, например так:

 

um = constant1 * 10;

2 - директива property

В MQL4 существуют заранее подготовленные переменные, называемые "Управляющие Компляцией", значения которых можно изменять для своей программы.

Для этого используется директива property - она говорит препроцессору, как настроить Ваш исполняемый файл *.ex4 .

Пример:

 

#property link  "[url="https://forum.alpari.com/redirector.php?url=https%3A%2F%2Fforum.alpari.com%2Fredirector.php%3Furl%3Dhttps%253A%252F%252Fforum.alpari.com%252Fredirector.php%253Furl%253Dhttp%25253A%25252F%25252Fwww.MYSITE.com"]http://www.MYSITE.com[/url]"
#property copyright   "FreeWare"

Список предопределённых переменных MQL4:

 



 

3 - директива include

Использование директивы include равносильно копированию всего содержимого подключаемого файла к себе в программу, в то место, где стоит эта директива. Ctrl+C -> Ctrl+V - только за Вас это делает препроцессор.

Пример:

 

#include <win32.h>

В этом примере Вы говорите препроцессору, открыть файл "win32.h", прочитать всё его содержимое и скопировать в то место, где стоит директива include.

 

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

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

- Можно указать имя файла в кавычках "win32.h" - тогда препроцессор будет искать этот файл в текущей директории - в той, где будет лежать Ваш код. Если Ваш код и искомый файл лежат в разных местах, то можно указать полный путь к файлу - это тоже делается с помощью кавычек: "F:\My_folder\My_include_files\Hello.h" .

Директиву include можно вставить в любую часть кода, но обычно это делается в самом начале.

 

Подсказка: Хорошей практикой является размещение часто употребляемого Вами кода в отдельном файле, для его дальнейшего подключения в свои программы.

(просто совет).

 

4 - директива import

Это как директива include, но есть различия.

Директива import используется только для подключения исполняемых файлов MQL4 (*.ex4) и динамических библиотек (*.dll), чтобы импортировать их функции в Вашу программу.

Например:

 

#import "user32.dll"
  int MessageBoxA(int hWnd,string lpText,string lpCaption,
        int uType);
  int MessageBoxExA(int hWnd,string lpText,string lpCaption,
       int uType,int wLanguageId);
#import "melib.ex4"
#import "gdi32.dll"
  int   GetDC(int hWnd);
  int   ReleaseDC(int hWnd,int hDC);
#import

Когда Вы импортируете функции из файла *.ex4 нет необходимости их объявлять.

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

Пример объявления функции:

 

int MessageBoxA(int hWnd,string lpText,string lpCaption, int uType);

Импорт функций начинается со строчки #include "имя файла" (или в угольных скобках).

Импорт йункций заканчивается строчкой #include .

 

Как говорит один знакомый информатик: "препроцессор помогает избежать работы обезьянкой". Этим всё сказано ;)

 

 

© Kirill. [email protected]

post-50854-1404214307,8787_thumb.gif

Edited by Programmer

Share this post


Link to post
Share on other sites
Programmer

Урок 10 - Ваш первый индикатор (часть 1)

 

Добро пожаловать в мир практических курсов MQL4; добро пожаловать в Ваш первый индикатор MQL4.

Уверен, этот и последующие несколько уроков будут интересны не только теоретикам, но и практикам.

 

Важно: рекомендую проситать предыдущие 9 уроков очень внимательно, прежде, чем переходить к этому подкурсу. Мы будем очень обширно

 

пользоваться пройденным материалом.

 

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

 

программирования на MQL4.

 

Он будет просто-напросто рассчитывать разницу High [] – Low []. Не торопитесь, скоро Вы всё поймёте.

 

Поехали!

 

 

MetaEditor

 

Это название той встроенной в MetaTrader 4 программы, которая позволяет Вам писать программы, читать помощь по MQL4, компилировать программы и

 

многое другое.

У меня на рабочем столе есть ярлык MetaEditor, чтобы проще его запускать.

Запуск MetaEditor - у Вас есть три возможности:

 

1 - Запустите MT4, затем либо нажмите F4, либо выберите MetaEditor из вкладки "сервис", либо нажмите на значок MetaEditor (см. рис. 1).

2 - Пуск -> Программы -> /Группа MetaTrader 4/ -> MetaEditor .

3 - Зайти в папку установки MT4 (например: C:\Program Files\MetaTrader 4), найти MetaEditor.exe и запустить (рекомедую сделать ярлык на рабочем

 

столе).

 



Рис. 1 - Стандартные кнопки MT4.

 

В любом случае Вы попадаете в программу MetaEditor 4.

 



Рис. 2 - Окна MetaEditor.

 

1 - Окно редактора. Здесь Вы пишите свою программу.

 

2 - Окно инструментария. Содержит четыре вкладки:

 

  • Ошибки. Здесь Вам покажут возникшие при компиляции ошибки.
  • Поиск в файлах. Здесь Вы можете просматривать файлы, найденные с помощью соотетствующей комманды из вкладки правка (Ctrl+Shift+F).
  • Библиотека. Online - библиотека.
  • Справка. Выделяете в коде нужное слово и жмёте F1. Появится справка.

 

 

3 - Окно навигатора. Содержит три вкладки:

 

  • Файлы. Для простого доступа к файлам, сохранённым в папке MT4.
  • Словарь. Доступ к справке по MQL4.
  • Поиск. Поиск в справке MQL4.

 

 

Советую ознакомиться с окнами MetaEditor.

 

А теперь приступим к созданию нашего первого индикатора.

 

Заметка: пользовательский индикатор - это программа, которая позволяет Вам использовать функции технического анализа, но не

 

может автоматизировать Ваши сделки.

 

 

Первые три шага

 

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

 

Шаг 1: Нажмите Файл -> Создать (или просто Ctrl + N)

 

Появится такое окошко:

 



Рис. 3 - окошко нового проекта.

 

Выберите пункт "пользовательский индикатор" и нажмите Next.

 

Шаг 2:

 

Появится такое окошко:

 



Рис. 4 - окошко свойств проекта.

 

1 - Имя Вашей программы.

 

2 - Автор программы.

 

3 - Ссылка на Ваш сайт или e-mail.

 

4 - Параметры - список внешних (extern) переменных. Это те переменные, которые пользователь сможет изменять в окошке настроек Вашего

 

индикатора (см. урок про переменные).

 

В нашем примере нам не потребуются внешние переменные. Заполните первые три поля и нажмите Next.

 

Шаг 3:

 

Появится такое окошко:

 



Рис. 5 - окошко свойств отображения индикатора.

 

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

 

индикатор (на графике цены или в отдельном окне).

 

1 - Индикатор в отдельном окне. Думаю, понятно, что эта опция делает.

 

2 - Минимум. Если индикатор рисутеся в отдельном окне, эта опция устанавливает нижнюю границу для этого окна.

 

3 - Максимум. Если индикатор рисутеся в отдельном окне, эта опция устанавливает верхнюю границу для этого окна.

 

4 - Список индексов. Сюда Вы добавляете линии индикатора и ставите их цвет-по-умолчанию.

 

В следующих уроках мы более подробно разберём эти опции, поэтому не спешите.

А сейчас сделайте всё, как на рис. 5.

 

Когда Вы нажмёте кнопку Finish, начнётся волшебство. Окошко помощника исчезнет, Вы опятьокажетесь в MetaEditor и... Угадайте....

Вы получили шаблон для своего первого индикатора.

 

Примерно такой код Вы получите:

 

//+------------------------------------------------------------------+
//|                                             MyFirstIndicator.mq4 |
//|                                                           Kirill |
//|                                          [email protected] |
//+------------------------------------------------------------------+
#property copyright "Kirill"
#property link      "[email protected]"

#property indicator_separate_window
#property indicator_buffers 1
#property indicator_color1 Red
//---- buffers
double ExtMapBuffer1[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
 {
//---- indicators
  SetIndexStyle(0,DRAW_LINE);
  SetIndexBuffer(0,ExtMapBuffer1);
//----
  return(0);
 }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
 {
//----

//----
  return(0);
 }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
 {
  int    counted_bars=IndicatorCounted();
//----

//----
  return(0);
 }
//+------------------------------------------------------------------+

Как Вы видите, помощник написал достаточно много кода за Вас.

В следующем уроке мы подробно разберём этот код, а на сегодня - всё.

 

© Kirill. [email protected]

post-50854-1404214307,9463_thumb.png

post-50854-1404214307,9562_thumb.gif

post-50854-1404214308,0293_thumb.gif

post-50854-1404214308,0652_thumb.gif

post-50854-1404214308,0995_thumb.gif

Edited by Programmer

Share this post


Link to post
Share on other sites
Programmer

Урок 11 - Ваш первый индикатор (часть 2)

 

Добро пожаловать на вторую часть урока "Ваш первый индикатор".

В предыдущем уроке мы не написали ни единой строчки кода - это за нас сделал "помощник". За что ему спасибо.

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

После этого мы разберём весь код строчку за строчкой.

 

Начнём кодить!

 

Я выделил жирным код, который нужно добавить.

 

//+------------------------------------------------------------------+

//| MyFirstIndicator.mq4 |

//| Kirill |

//| [email protected] |

//+------------------------------------------------------------------+

#property copyright "Kirill"

#property link "[email protected]"

#property indicator_separate_window

#property indicator_buffers 1

#property indicator_color1 Red

//---- buffers

double ExtMapBuffer1[];

//+------------------------------------------------------------------+

//| Custom indicator initialization function |

//+------------------------------------------------------------------+

int init()

{

//---- indicators

SetIndexStyle(0,DRAW_LINE);

SetIndexBuffer(0,ExtMapBuffer1);

 

string short_name = "Your first indicator is running!";

IndicatorShortName(short_name);

//----

return(0);

}

//+------------------------------------------------------------------+

//| Custom indicator deinitialization function |

//+------------------------------------------------------------------+

int deinit()

{

//----

 

//----

return(0);

}

//+------------------------------------------------------------------+

//| Custom indicator iteration function |

//+------------------------------------------------------------------+

int start()

{

int counted_bars=IndicatorCounted();

//---- check for possible errors

if (counted_bars<0) return(-1);

//---- last counted bar will be recounted

if (counted_bars>0) counted_bars--;

int pos=Bars-counted_bars;

double dHigh , dLow , dResult;

Comment("Hi! I'm here on the main chart window!");

//---- main calculation loop

while(pos>=0)

{

dHigh = High[pos];

dLow = Low[pos];

dResult = dHigh - dLow;

ExtMapBuffer1[pos]= dResult ;

pos--;

}

//----

return(0);

}

//+------------------------------------------------------------------+

 

Как он будет работать?

 

Код:

//+------------------------------------------------------------------+
//|                                             MyFirstIndicator.mq4 |
//|                                                           Kirill |
//|                                          [email="[email protected]"][email protected][/email] |
//+------------------------------------------------------------------+

 

Разбор:

Комментарии

Первые пять строчек (выделены серым цветом у Вас в редакторе) - это комментарии.

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

Есть много причин, по которым могут потребоваться комментарии:

- Сделать код более красивым.

- Задокументировать такие моменты, как право собственности, дату создания и т.д.

- Сделать код понятнее.

- Объяснить, как код работает.

- ...

Комментарии бывают однострочные и многострочные (см. урок 2 - Синтаксис).

В нашей программе помощник собрал введённую нами информацию о названии программы, её авторе и ссылке в самом верху.

 

Код:

 

#property copyright "Kirill"
#property link      "[email="[email protected]"][email protected][/email]"
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_color1 Red

 

Разбор:

Директива property . (см. урок 9)

#property copyright - здесь хранится имя автора программы. Вы ввели его на втором шаге помощника. Тип данных - string.

#property link - ссылка на Вашу домашнюю страницу или Ваш e-mail. Эти данные Вы также ввели на втором шаге помощника. Тип данных - string.

#property indicator_separate_window - таким образом мы говорим препроцессору, что мы хотим, чтобы наш индикатор рисовался в отдельном окне. Тип данных - void (нет принимаемого значения).

* #property indicator_chart_window - алтернатива - индикатор рисуется в окне графика. Обе опции использовать одновременно нельзя.

#property indicator_buffers 1 - с помощью indicator_buffers мы устанавливаем количество массивов, выделяемых под линии нашего индикатора. В кажлом индикаторе разрешается не больше 8 линий. В нашем случае мы рисуем только одну линию.

#property indicator_color1 Red - indicator_colorN устанавливает цвет линии номер N. Пользователь может изменить этот цвет в настройках индикатора. Тип данных - color.

 

Код:

 

//---- buffers
double ExtMapBuffer1[];

 

Разбор:

Массивы (Arrays)

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

Массив - это упорядоченное множество элементов одного типа. Нумерация в массиве начинается с нуля.

Объявление массива:

 

int my_array[50];

 

Здесь мы объявили массив, в котором может содержатся до 50 (включительно) элементов типа integer.

Доступ к элементу происходит по его индексу.

Например, доступ к 0-вому элементу массива и присваивания ему значения 16 выглядит так:

 

my_array[0] = 16;

 

Массив можно инициализировать в строчке его объявления. Делается это так:

 

int my_array[5] = {16,24,15,8901,17}

 

В нашей программе используется такой код:

 

double ExtMapBuffer1[];

 

Таким образом мы объявили массив типа double. Этот массив мы будем использовать для подсчёта значений, которые необходимо рисовать на графике индикатора.

 

Код:

 

int init()

 

Разбор:

В MQL4 есть три спец. функции: init(), start(), deinit(). Подробнее - см. урок 7 - Функции.

 

Код:

 

//---- indicators
  SetIndexStyle(0,DRAW_LINE);
  SetIndexBuffer(0,ExtMapBuffer1);

[b]string short_name = "Your first indicator is running!";[/b]
[b]IndicatorShortName(short_name);[/b]
//----

 

Разбор:

 

Функции пользовательских индикаторов.

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

 

SetIndexStyle():

void SetIndexStyle( int index, int type, int style=EMPTY, int width=EMPTY, color clr=CLR_NONE)

- Устанавливает новый тип, стиль, ширину и цвет для указанной линии индикатора.

index - Порядковый номер линии. Должен быть от 0 до 7. Это потому что у нас может быть всего 8 линий, а нумерация в массиве, где они хранятся начинается с нуля.

type - Стиль отрисовки линии индикатора. Может быть одним из перечисленных стилей отрисовки линии:

DRAW_LINE - Простая линия

DRAW_SECTION - Отрезки между непустыми значениями линии

DRAW_HISTOGRAM - Гистограмма

DRAW_ARROW - Стрелки (символы)

DRAW_ZIGZAG - Отрезки между непустыми значениями чётной и нечётной линий (зигзаг)

DRAW_NONE - Отсутствие какого-либо рисования

style - Стиль линии. Используется для линий толщиной в 1 пиксель. Может быть одним из перечисленных стилей линии. Пустое значение (EMPTY) указывает, что стиль не будет изменен.

DRAW_LINE - Простая линия

DRAW_SECTION - Отрезки между непустыми значениями линии

DRAW_HISTOGRAM - Гистограмма

DRAW_ARROW - Стрелки (символы)

DRAW_ZIGZAG - Отрезки между непустыми значениями чётной и нечётной линий (зигзаг)

DRAW_NONE - Отсутствие какого-либо рисования

width - Ширина линии. Допустимые значения - 1,2,3,4,5. Пустое значение (EMPTY) указывает, что ширина не будет изменена.

clr - Цвет линии. Отсутствие параметра означает, что цвет не будет изменен.

В нашем коде:

SetIndexStyle(0,DRAW_LINE);

index = 0 - это означает, что мы будем работать с первой (и единственной) нашей линией.

type = DRAW_LINE - это означает, что мы хотим рисовать линию.

Остальные параметры мы оставили по умолчанию.

 

SetIndexBuffer()

bool SetIndexBuffer(int index, double array[])

- Связывает переменную-массив, объявленный на глобальном уровне, с предопределенным буфером пользовательского индикатора. Количество буферов, необходимых для расчета индикатора, задается с помощью функции IndicatorBuffers() и не может быть больше 8. В случае успешного связывания возвращается TRUE, иначе FALSE. Чтобы получить расширенные сведения об ошибке, следует вызвать функцию GetLastError().

Как мы уже замечали ранее, расчитанные данные для отрисовки на график в нашей программе будут храниться в массиве ExtMapBuffer1[]. Его мы и связываем с нашей единственной линией, имеющей индекс 0.

 

IndicatorShortName();

void IndicatorShortName(string name)

- Установка "короткого" имени пользовательского индикатора для отображения в подокне индикатора и в окне DataWindow.

Мы в нашей программе завели переменную short_name типа string, которой присвоили значение "Your first indicator is running!". Затем мы передали эту переменную в функцию IndicatorShortName(); .

 

Код:

 

return (0);

 

Разбор:

Функция init() возвращает 0 и завершает свою работу. Управление переходит функции start().

 

Код:

 

int deinit()
 {
//----

//----
  return(0);
 }

 

Разбор:

Ничего нового про функцию deinit() сказать не могу.

 

Мы продолжим разбирать код в следующем уроке. Надеюсь, Вам понравилось, и я приветствую любые Ваши вопросы.

До встречи!

 

 

© Kirill. [email protected]

Share this post


Link to post
Share on other sites
Programmer

Урок 12 - Ваш первый индикатор (часть 3)

 

Добро пожаловать на третью часть урока "Ваш первый индикатор".

В предыдущем уроке мы разбирали код нашего первого индикатора строчку за строчкой и дошли до функции start().

Очень надеюсь, что Вы прекрасно понимаете, что происходило в предыдущих уроках.

 

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

Вы готовы? Давайте разберём оставшийся код!

 

Наш код:

 

//+------------------------------------------------------------------+

//| MyFirstIndicator.mq4 |

//| Kirill |

//| [email protected] |

//+------------------------------------------------------------------+

#property copyright "Kirill"

#property link "[email protected]"

#property indicator_separate_window

#property indicator_buffers 1

#property indicator_color1 Red

//---- buffers

double ExtMapBuffer1[];

//+------------------------------------------------------------------+

//| Custom indicator initialization function |

//+------------------------------------------------------------------+

int init()

{

//---- indicators

SetIndexStyle(0,DRAW_LINE);

SetIndexBuffer(0,ExtMapBuffer1);

 

string short_name = "Your first indicator is running!";

IndicatorShortName(short_name);

//----

return(0);

}

//+------------------------------------------------------------------+

//| Custom indicator deinitialization function |

//+------------------------------------------------------------------+

int deinit()

{

//----

 

//----

return(0);

}

//+------------------------------------------------------------------+

//| Custom indicator iteration function |

//+------------------------------------------------------------------+

int start()

{

int counted_bars=IndicatorCounted();

//---- check for possible errors

if (counted_bars<0) return(-1);

//---- last counted bar will be recounted

if (counted_bars>0) counted_bars--;

int pos=Bars-counted_bars;

double dHigh , dLow , dResult;

Comment("Hi! I'm here on the main chart windows!");

//---- main calculation loop

while(pos>=0)

{

dHigh = High[pos];

dLow = Low[pos];

dResult = dHigh - dLow;

ExtMapBuffer1[pos]= dResult ;

pos--;

}

//----

return(0);

}

//+------------------------------------------------------------------+

 

Код:

int start()
 {
  }

 

Разбор:

Как я Вам уже говорил, мы будем проводить 90% нашей программистской жизни внутри фигурных скобок тела функции start(). Это так, потому что она самая важная из всех трёх спец. функций MQL4. В отличии от функций init() и deinit() функция start() не будет вызвана (клиентским терминалом) только единожды. Она будет вызываться при каждом поступление новых котировок. Функция start() возвращает значение типа integer, как и все остальные спец. функции языка MQL4. 0 означает, что функция отработала без ошибок, а любое другое число означает, что произошла ошибка.

 

Код:

 

  int    counted_bars=IndicatorCounted();

 

Разбор:

Здесь мы объявили переменную counted_bars типа integer и инициализировали её значением, возвращаемым функцией IndicatorCounted(); .

 

int IndicatorCounted( )

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

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

 

ОЧЕНЬ ВАЖНО: на будущее запомните, что в MQL4 бары нумеруются задом-наперёд. Нулевой бар - это текущий бар, следующий (более старый - левее на графике) - это первый бар, за ним - второй и т.д. При появлении нового бара они все перенумеровываются, и текущий опять становится нулевым.

 

Код:

 

//---- check for possible errors
  if (counted_bars<0) return(-1);

 

Разбор:

Очевидно, что число баров, не измененных после последнего вызова индикатора должно быть = 0 или > 0. Если же оно < 0, значит произошла ошибка. Мы терминируем функцию start() и сообщаем об ошибке, возвращая не 0.

 

Код:

 

//---- last counted bar will be recounted
  if (counted_bars>0) counted_bars--;

 

Разбор:

Притворяемся, что посчитано на один бар меньше, чтобы пересчитать последний бар. На самом деле, это перестраховка, т.к. функция IndicatorCounted( ) и так возвращает число на 1 меньше. Но ничего страшного в том, что мы пересчитаем ещё один лишний бар нет. PS: надеюсь, вы помните, что --; - это оператор декремента - уменьшение на единицу.

 

Код:

 

  int pos=Bars-counted_bars;

 

Разбор:

Здесь мы объявляем переменную pos, которая указывает, сколько раз должен сработать наш счётный цикл (про цикл while см. далее). 'Функция' Bars возвращает количество уже имеющихся на графике баров. Чтобы вычислить pos мы из общего количества баров графика вычитаем количество уже посчитанных баров.

 

Кстати, хороший момент обсудить 'функцию' Bars и её братьев.

 

 

(продолжение в след. посте)

Share this post


Link to post
Share on other sites
Programmer

Предопределённые переменные языка MQL4:

 

 

Ask, Bid, Bars, Close, Open, High, Low, Time и Volume - являются функциями, хотя в MQL4 они называются предопределёнными переменными и после них не надо ставить круглые скобки.

И я докажу Вам, что они скорее функции, чем переменные.

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

Функция - означает сделать что-то и вернуть какое-то значение. Например, Bars считает и возвращает количество баров на графике. Так что же? Это переменная?

Если ввести следующий код:

Bars = 1;

Вы получите ошибку: 'Bars' - unexpected token

Это потому что они не переменные, и Вы не можете присваивать им значения.

Итак, обсудим эти функции.

 

int Bars

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

 

double Ask

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

 

double Bid

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

 

Замечание: Например, USD/JPY = 105.11/105.14 - здесь левая цена - это bid (цена, по которой Вы продаёте), правая цена - это ask (цена, по которой Вы покупаете).

 

double Open[]

Эта функция возвращает значение типа double, в котором содержится информация о цене открытия (далее - везде 'цена' - это bid) для указанного бара.

Например: Open[0] вернёт цену открытия текущего бара.

 

double Close[]

Эта функция возвращает значение типа double, в котором содержится информация о цене закрытия для указанного бара.

Замечание: Т.к. цена закрытия текущего бара ещё никому не известна, Close[0] возвращает текущую цену bid.

 

double High[]

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

 

double Low[]

Эта функция возвращает значение типа double, в котором содержится информация о самой низкой цене (цене low) для указанного бара.

 

double Volume[]

Эта функция возвращает значение типа double, в котором содержится информация ( для forex объёмы не контролируются, поэтому: ) о количестве изменений котировки для указанного бара.

 

int Digits

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

 

int Point

Эта функция возвращает значение типа double равное одному пункту для данной валютной пары. Обычно 0.0001 .

 

datetime Time[]

Эта функция возвращает значение типа datetime, в котором содержится информация о времени открытия указанного бара.

 

Код:

 

  double dHigh , dLow , dResult;

Разбор:

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

 

Код:

 

  Comment("Hi! I'm here on the main chart window!");

Разбор:

В этой строчке мы используем функцию Comment, чтобы распечатать текст "Hi! I'm here on the main chart window!" в левом верхнем углу основного графика.

Всего таких информирующих функции три:

 

void Comment()

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

 

void Print( ...)

- Печатает некоторое сообщение в журнал экспертов. Параметры могут иметь любой тип. Количество параметров не может превышать 64.

 

void Alert( ...)

- Отображает диалоговое окно, содержащие пользовательские данные. Параметры могут быть любого типа. Количество параметров не может превышать 64.

 

Код:

 

//---- main calculation loop
  while(pos>=0)
  {
     dHigh = High[pos];
     dLow = Low[pos];
     dResult = dHigh - dLow;
     ExtMapBuffer1[pos]= dResult ;
     pos--;
  }

Разбор:

Пришло время войти в цикл расчёта отображаемых нашим индикатором точек. Любое значение, которое мы положим в массив ExtMapBuffer1[] будет отображено на графике (потому что, используя функцию SetIndexBuffer(), мы связали этот массив с линией, индексируемой нулём).

 

ОЧЕНЬ ВАЖНО: когда мы связываем массив с линией, массив приобретает ещё одно спец. свойство. При появлении нового бара на графике, все элементы массива сдвигаются влево на один, т.е. N-й становится N+1-ым, ... , 1-й становится 2-м, 0-й становится 1-м. Таким образом, высвобождается место для нового нулевого элемента. Это сделано для того, чтобы при пересчёте только новых баров графика, информация о значении индикатора на старых барах сохранялась в элементах масива, индексируемых теми же числами, что и сами бары.

 

Переменной цикла (она регулирует число его прохождений) у нас является переменная pos. Мы её используем для обращения к неподсчитанным барам. Например High[pos] вернёт максимальное значение цены на баре с индексом pos.

В теле цикла мы присваиваем переменной dHigh значение цены high на баре pos.

Аналогично, мы присваиваем переменной dLow значение цены low на баре pos.

Разницу dHigh - dLow мы присваиваем переменной dResult.

Затем Мы используем dResult для отрисовки линии индикатора, присваивая его значение соответствующему элементу массива ExtMapBuffer1[] (элементу с индексом pos).

Последняя строчка цикла - мы применяем оператор декремента к переменной цикла pos. Когда, pos станет = -1, цикл завершит свою работу.

 

Наконец-то мы можем скомпилировать наш индикатор!

 

Нажмите F5 или нажмите кнопку Компилировать.

В результате сгенерируется исполняемый файл "MyFirstIndicator.ex4", который Вы можете запустить в своём терминале.

Чтобы это сделать нажмите F4 или вручную откройте терминал. В окне навигатора в терминале выберите раздел "Пользовательские Индикаторы", найдите MyFirstIndicator и перетащите его на график цены.

 

Замечание: Ваш индикатор показывает волатильность рынка.

 

 

 

Надеюсь, Вам понравился Ваш первый индикатор.

Готовьтесь к следующему уроку и к следующему шагу в мир практического MQL4 - Ваш первый Торговый Советник.

До скорых встреч!

 

 

© Kirill. [email protected]

post-50854-1404214308,1366_thumb.gif

Edited by Programmer

Share this post


Link to post
Share on other sites
Programmer

Урок 13 - Ваш первый советник

 

В предыдущих уроках мы создали наш первый индикатор. Хоть он и не был полезен нам как трейдерам, он был весьма полезен нам как программистам.

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

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

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

Можно кого-нибудь нанять, чтобы он следил за терминалом и звонил Вам каждые 5 минут, чтобы рассказать, что происходит. Если этот человек профессионал, то Вы будете тратить на него всю свою прибыль. А если он новичок, то Вы потратете на него весь свой каптал.

 

Вторая опция - автоматизировать свою торговлю.

Именно для этого нужны советники - они же торговые эксперты - они же механические торговые системы (МТС).

 

Советник - это программа, написанная на MQL4 (ведь мы изучаем MQL4, верно?), которая использует Ваши любимые индикаторы и торговые методы для автоматизации Ваших торгов.

Он покупает, продаёт и модифицирует ордера за Вас.

Сегодня мы создадим нашего первого торгового советника.

Начнём!

 

Первые два шага:

 

Шаг 1:

Если Вы ещё не открыли свой MetaEditor, то пора бы это сделать. Затем выберите Файл->Создать (или просто нажмите CTRL+N).

Появится помощник (как при создании первого индикатора).

На этот раз надо выбрать пункт "Советник".

 



Рис. 1 - Помощник. 1й шаг.

 

Шаг 2:

После нажатия кнопки "Next", Вы окажетесь в окошке общих параметров советника.

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

На этом шаге можно задать следующие свойства:

 

1 - Имя. Название Вашего советника. Мы назовём его My_first_EA.

 

2 - Автор. Имя автора. Введите своё имя.

 

3 - Ссылка. Ссылка на Ваш сайт или e-mail.

 

4 - Параметры:

Это список внешних (extern) параметров. Это те параметры, которые пользователь сможет менять из окошка настроек советника.

Для добавления нового параметра нажмите кнопку "Добавить". Нажатие этой конпки приведёт к появлению новой записи в списке внешних переменных. Каждая переменная имеет три поля:

Имя: двойной щелчок по этому полю позволит Вам задать имя (идентификатор) переменной.

Тип: двойной щелчок по этому полю позволит Вам задать тип переменной.

Начальное значение: двойной щелчок по этому полю позволит Вам задать начальное значение переменной.

Последнее поле является опциональным, что означает, что его можно оставить пустым.

В нашем случае, мы добавим три переменные:

 



Рис. 2 - Помощник. 2й шаг.

 

Теперь нажмите кнопку "Finish". MetaEditor перенесёт Вас к коду, подготовленному помощником и сохранит его в файл My_first_EA.mq4 в папке MetaTrader4\experts.\

Замечание: торговых советников надо клоасть в папку MetaTrader4\experts, а индикаторы - в папку MetaTrader4\experts\indicators, иначе они не будут работать.

 

Помощник подготовил следующий код:

 

//+------------------------------------------------------------------+
//|                                                  My_First_EA.mq4 |
//|                                                           Kirill |
//|                                          [email="[email protected]"][email protected][/email] |
//+------------------------------------------------------------------+
#property copyright "Kirill"
#property link      "[email="[email protected]"][email protected][/email]"
//---- input parameters
extern double    TakeProfit=350.0;
extern double    Lots=0.1;
extern double    TrailingStop=35.0;
//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
 {
//----

//----
  return(0);
 }
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
 {
//----

//----
  return(0);
 }
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
 {
//----

//----
  return(0);
 }
//+------------------------------------------------------------------+

(продолжение в след. посте)

post-50854-1404214308,2064_thumb.gif

post-50854-1404214308,2423_thumb.gif

Edited by Programmer

Share this post


Link to post
Share on other sites
Programmer

Теперь добавим свой код:

 

//+------------------------------------------------------------------+
//|                                                  My_First_EA.mq4 |
//|                                                           Kirill |
//|                                          [email="[email protected]"][email protected][/email] |
//+------------------------------------------------------------------+
#property copyright "Kirill"
#property link      "[email="[email protected]"][email protected][/email]"
//---- input parameters
extern double    TakeProfit=350.0;
extern double    Lots=0.1;
extern double    TrailingStop=35.0;
//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
 {
//----

//----
  return(0);
 }
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
 {
//----

//----
  return(0);
 }
int Crossed (double line1 , double line2)
{
  static int last_direction = 0;
  static int current_dirction = 0;
  if(line1>line2)current_dirction = 1; //up
  if(line1<line2)current_dirction = 2; //down
  if(current_dirction != last_direction) //changed
  {
     last_direction = current_dirction;
     return (last_direction);
  }
  else
  {
     return (0);
  }
}
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
{
//----
  int cnt, ticket, total;
  double shortEma, longEma;
  if(Bars<100)
  {
     Print("bars less than 100");
     return(0);
  }
  if(TakeProfit<10)
  {
     Print("TakeProfit less than 10");
     return(0); // check TakeProfit
  }
  shortEma = iMA(NULL,0,8,0,MODE_EMA,PRICE_CLOSE,0);
  longEma = iMA(NULL,0,13,0,MODE_EMA,PRICE_CLOSE,0);
  int isCrossed = Crossed (shortEma,longEma);
  total = OrdersTotal();
  if(total < 1)
  {
     if(isCrossed == 1)
     {
        ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,0,Ask+TakeProfit*Point, "My EA",12345,0,Green);
        if(ticket>0)
        {
           if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
              Print("BUY order opened : ",OrderOpenPrice());
        }
        else Print("Error opening BUY order : ",GetLastError());
           return(0);
     }
     if(isCrossed == 2)
     {
        ticket=OrderSend(Symbol(),OP_SELL,Lots,Bid,3,0,
        Bid-TakeProfit*Point,"My EA",12345,0,Red);
        if(ticket>0)
        {
           if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
              Print("SELL order opened : ",OrderOpenPrice());
        }
        else Print("Error opening SELL order : ",GetLastError());
           return(0);
     }

  return(0);
  }
  for(cnt=0;cnt<total;cnt++)
  {
     OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
     if(OrderType()<=OP_SELL && OrderSymbol()==Symbol())
     {
        if(OrderType()==OP_BUY) // long position is opened
        {
        // should it be closed?
           if(isCrossed == 2)
           {
              OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet);   // close position
              return(0); // exit
           }

        // check for trailing stop
           if(TrailingStop>0)
           {
              if(Bid-OrderOpenPrice()>Point*TrailingStop)
              {
                 if(OrderStopLoss()<Bid-Point*TrailingStop)
                 {
                    OrderModify(OrderTicket(),OrderOpenPrice(),Bid-Point*TrailingStop,OrderTakeProfit(),0,Green);
                    return(0);
                 }
              }
           }
        }

        else // go to short position
        {
        // should it be closed?
           if(isCrossed == 1)
           {
              OrderClose(OrderTicket(),OrderLots(),Ask,3,Violet);   // close position
              return(0); // exit
           }

        // check for trailing stop
           if(TrailingStop>0)
           {
              if((OrderOpenPrice()-Ask)>(Point*TrailingStop))
              {
                 if((OrderStopLoss()>(Ask+Point*TrailingStop)) || (OrderStopLoss()==0))
                 {
                    OrderModify(OrderTicket(),OrderOpenPrice(),Ask+Point*TrailingStop,OrderTakeProfit(),0,Red);
                    return(0);
                 }
              }
           }
        }
     }
  }

  return(0);
}
//+------------------------------------------------------------------+

Можно скопировать код прямо отсюда.

Скомпилируйте эксперта, например, нажав F5.

 

Напуганы?

Не бойтесь этих 170 строчек кода, что Вы видите выше. Скоро мы их разберём строчка-за-строчкой. Это очень просто.

 

Протестируйте МТС:

Прежде, чем разбирать код, проверим прибыльна ли созданная МТС.

Замечание: эта МТС предназначена для работы с EUR/USD на ТФ H4.

Протестировать эксперта можно двумя способами:

 

1 - Online-торговля

При online-торговле результаты теста точнее, но надо потратить дни или даже месяцы, чтобы выяснить прибыльна или нет данная МТС.

Для начала, необходимо разрешить советнику автоматизировать Вашу торговлю.

В MetaTrader4 выберите Сервис -> Настройки (или просто нажмите CTRL+O).

Во вкладке Советники разрешите следующие опции:

Включить советники

Разрешить советнику торговать

И нажмите кнопку "OK".

 



Рис.3 - Разрешаем автоторговлю.

 

Теперь найдите своего эксперта в Навигаторе в разделе Советники и перетащите его на график EUR/USD H4.

 



Рис.4 - Советник включён.

 

2 - тестер стратегий

Второй метод тестирования МТС - это тестер стратегий. Он менее аккуратен, но зато занимает намного меньше времени. Об этом методе мы подробно поговорим позже.

Сейчас просто вызовем его окошко, нажав F6.

Выберете параметры как на рисунке:

 



Рис.5 - Настройки тестера.

 

Нажмите кнопку Старт.

Далее Вас интересует вкладка отчёт.

Вникайте!

 

 

© Kirill. [email protected]

post-50854-1404214308,2811_thumb.gif

post-50854-1404214308,3129_thumb.gif

post-50854-1404214308,3812_thumb.jpg

Edited by Programmer

Share this post


Link to post
Share on other sites
Programmer

Урок 14 - Ваш первый советник (часть 2)

 

Добро пожаловать на вторую часть серии уроков по созданию Вашего первого советника.

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

Вы готовы? Начнём!

 

Замечание: Наш советник предназначен для обучения и не будет (не нацелен на) извлекать прибыль.

 

Код, который у нас уже есть:

 

//+------------------------------------------------------------------+
//|                                                  My_First_EA.mq4 |
//|                                                           Kirill |
//|                                          [email="[email protected]"][email protected][/email] |
//+------------------------------------------------------------------+
#property copyright "Kirill"
#property link      "[email="[email protected]"][email protected][/email]"
//---- input parameters
extern double    TakeProfit=350.0;
extern double    Lots=0.1;
extern double    TrailingStop=35.0;
//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
 {
//----

//----
  return(0);
 }
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
 {
//----

//----
  return(0);
 }
int Crossed (double line1 , double line2)
{
  static int last_direction = 0;
  static int current_dirction = 0;
  if(line1>line2)current_dirction = 1; //up
  if(line1<line2)current_dirction = 2; //down
  if(current_dirction != last_direction) //changed
  {
     last_direction = current_dirction;
     return (last_direction);
  }
  else
  {
     return (0);
  }
}
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
{
//----
  int cnt, ticket, total;
  double shortEma, longEma;
  if(Bars<100)
  {
     Print("bars less than 100");
     return(0);
  }
  if(TakeProfit<10)
  {
     Print("TakeProfit less than 10");
     return(0); // check TakeProfit
  }
  shortEma = iMA(NULL,0,8,0,MODE_EMA,PRICE_CLOSE,0);
  longEma = iMA(NULL,0,13,0,MODE_EMA,PRICE_CLOSE,0);
  int isCrossed = Crossed (shortEma,longEma);
  total = OrdersTotal();
  if(total < 1)
  {
     if(isCrossed == 1)
     {
        ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,0,Ask+TakeProfit*Point, "My EA",12345,0,Green);
        if(ticket>0)
        {
           if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
              Print("BUY order opened : ",OrderOpenPrice());
        }
        else Print("Error opening BUY order : ",GetLastError());
           return(0);
     }
     if(isCrossed == 2)
     {
        ticket=OrderSend(Symbol(),OP_SELL,Lots,Bid,3,0,
        Bid-TakeProfit*Point,"My EA",12345,0,Red);
        if(ticket>0)
        {
           if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
              Print("SELL order opened : ",OrderOpenPrice());
        }
        else Print("Error opening SELL order : ",GetLastError());
           return(0);
     }

  return(0);
  }
  for(cnt=0;cnt<total;cnt++)
  {
     OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
     if(OrderType()<=OP_SELL && OrderSymbol()==Symbol())
     {
        if(OrderType()==OP_BUY) // long position is opened
        {
        // should it be closed?
           if(isCrossed == 2)
           {
              OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet);   // close position
              return(0); // exit
           }

        // check for trailing stop
           if(TrailingStop>0)
           {
              if(Bid-OrderOpenPrice()>Point*TrailingStop)
              {
                 if(OrderStopLoss()<Bid-Point*TrailingStop)
                 {
                    OrderModify(OrderTicket(),OrderOpenPrice(),Bid-Point*TrailingStop,OrderTakeProfit(),0,Green);
                    return(0);
                 }
              }
           }
        }

        else // go to short position
        {
        // should it be closed?
           if(isCrossed == 1)
           {
              OrderClose(OrderTicket(),OrderLots(),Ask,3,Violet);   // close position
              return(0); // exit
           }

        // check for trailing stop
           if(TrailingStop>0)
           {
              if((OrderOpenPrice()-Ask)>(Point*TrailingStop))
              {
                 if((OrderStopLoss()>(Ask+Point*TrailingStop)) || (OrderStopLoss()==0))
                 {
                    OrderModify(OrderTicket(),OrderOpenPrice(),Ask+Point*TrailingStop,OrderTakeProfit(),0,Red);
                    return(0);
                 }
              }
           }
        }
     }
  }

  return(0);
}
//+------------------------------------------------------------------+

 

(продолжение в след. посте)

Share this post


Link to post
Share on other sites
Programmer

Идея ТС нашего эксперта.

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

Наш советник прост и проста его идея. Рассмотрим её.

Используются две средние типа EMA (Exponential Moving Average): EMA 8 (быстрая) и EMA 13 (медленная).

 

Открытие позиций:

Наш советник будет открывать позиции при пересечении средних. Причём направление пересечения определяет в какую сторону будет открыта позиция.

Если быстрая EMA после пересечения окажется выше медленной EMA, то откроется сделка BUY (long).

Если быстрая EMA после пересечения окажется ниже медленной EMA, то откроется сделка SELL (short).

Одновременно может быть открыта только одна сделка.

 

Закрытие позиций:

Наш советник будет закрывать позиции при обратном пересечении средних.

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

 

Модификация позиций:

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

 

//---- input parameters
extern double    TakeProfit=350.0;
extern double    Lots=0.1;
extern double    TrailingStop=35.0;

 

В приведённых строчках помощник объявил три внешние переменные, как мы его и попросили. Эти переменные пользователь может изменять в окошке настроек эксперта. Также они проинициализированы значениями по умолчанию.

 

int Crossed (double line1 , double line2)
{
  static int last_direction = 0;
  static int current_dirction = 0;
  if(line1>line2)current_dirction = 1; //up
  if(line1<line2)current_dirction = 2; //down
  if(current_dirction != last_direction) //changed
  {
     last_direction = current_dirction;
     return (last_direction);
  }
  else
  {
     return (0);
  }
}

 

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

Функция Crossed принимает на вход две переменные типа double и возвращает переменную типа integer. Первый параметр - это тек. значение первой линии (в нашем случае - быстрой EMA). Второй параметр - это тек. значение второй линии (в нашем случае - медленной EMA).

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

- Функция возвращает 0, если взаиморасположение линий не изменилось.

- Функция возвращает 1, если взаиморасположение линий изменилось, и первая линия оказалась над второй.

- Функция возвращает 2, если взаиморасположение линий изменилось, и первая линия оказалась под второй.

 

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

 

Посмотрим - как мы написали эту функцию?

int Crossed (double line1 , double line2)

Это объявление функции. Оно означает, что мы хотим создать функцию с именем Crossed, которая принимает на вход два параметра типа double и возвращает integer. Когда Вы будете вызывать эту функцию, ей надо быдет передавать два параметра типа double, а возвращать Вам она будет integer. Функцию необходимо объявлять перед её использованием (вызовом).

Расположение кода функции значения не имеет. Я его поставил гад функцией start(), Вы можете поставить его где угодно.

   static int last_direction = 0;
  static int current_dirction = 0;

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

 

if(current_dirction != last_direction) //changed

 

В этой строчке мы сравниваем две статические переменные. Если current_dirction не равен last_direction, это значит, что взаиморасположение претерпело изменение.

 

      last_direction = current_dirction;
     return (last_direction);

 

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

 

else
  {
     return (0);
  }

 

В противном случае (взаиморасположение линий не изменилось) необходимо вернуть 0.

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

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

 

Удачи!

 

 

© Kirill. [email protected]

Share this post


Link to post
Share on other sites
Programmer

Урок 15 - Торговые функции

 

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

Для начала мы разберём самую главную функцию - OrderSend(). А затем - все остальные в алфавитном порядке.

Готовы? Поехали!

 

1 - OrderSend()

Синтаксис:

int OrderSend( string symbol, int cmd, double volume, double price, int slippage, double stoploss, double takeprofit, string comment=NULL, int magic=0, datetime expiration=0, color arrow_color=CLR_NONE)

Описание:

Основная функция, используемая для открытия позиции или установки отложенного ордера.

Возвращает номер тикета, который назначен ордеру торговым сервером или -1 в случае неудачи. Чтобы получить дополнительную информацию об ошибке, необходимо вызвать функцию GetLastError().

Замечания.

При открытии рыночного ордера (OP_SELL или OP_BUY) в качестве цены открытия могут использоваться только самые последние цены Bid (для продажи) или Ask (для покупки). Если операция проводится по финансовому инструменту, отличному от текущего, то для получения последних котировок по этому инструменту необходимо воспользоваться функцией MarketInfo() с параметром MODE_BID или MODE_ASK. Нельзя использовать расчетную либо ненормализованную цену. Если запрашиваемой цены открытия не было в ценовом потоке либо запрашиваемая цена не нормализована в соответствии с количеством знаков после десятичной точки, то будет сгенерирована ошибка 129 (ERR_INVALID_PRICE). Если запрашиваемая цена открытия сильно устарела, то независимо от значения параметра slippage будет сгенерирована ошибка 138 (ERR_REQUOTE). Если же запрашиваемая цена устарела, но ещё присутствует в ценовом потоке, то позиция открывается по текущей цене и только в том случае, если текущая цена попадает в диапазон price+-slippage.

Цены StopLoss и TakeProfit не могут располагаться слишком близко к рынку. Минимальное расстояние стопов в пунктах можно получить, используя функцию MarketInfo() с параметром MODE_STOPLEVEL. В случае ошибочных, а также ненормализованных стопов генерируется ошибка 130 (ERR_INVALID_STOPS).

При установке отложенного ордера цена открытия не может быть слишком близкой к рынку. Минимальное расстояние отложенной цены от текущей рыночной цены в пунктах также можно получить, используя функцию MarketInfo() с параметром MODE_STOPLEVEL. В случае неправильной цены открытия отложенного ордера будет сгенерирована ошибка 130 (ERR_INVALID_STOPS).

На некоторых торговых серверах может быть установлен запрет на применение срока истечения отложенных ордеров. В этом случае при попытке задать ненулевое значение в параметре expiration будет сгенерирована ошибка 147 (ERR_TRADE_EXPIRATION_DENIED).

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

Параметры:

symbol - Наименование финансового инструмента, с которым проводится торговая операция.

cmd - Торговая операция. Может быть любым из значений торговых операций.

volume - Количество лотов.

price - Цена открытия.

slippage - Максимально допустимое отклонение цены для рыночных ордеров (ордеров на покупку или продажу).

stoploss - Цена закрытия позиции при достижении уровня убыточности (0 в случае отсутствия уровня убыточности).

takeprofit - Цена закрытия позиции при достижении уровня прибыльности (0 в случае отсутствия уровня прибыльности).

comment - Текст комментария ордера. Последняя часть комментария может быть изменена торговым сервером.

magic - Магическое число ордера. Может использоваться как определяемый пользователем идентификатор.

expiration - Срок истечения отложенного ордера.

arrow_color - Цвет открывающей стрелки на графике. Если параметр отсутствует или его значение равно CLR_NONE, то открывающая стрелка не отображается на графике.

Торговые операции:

 

 

 

2 - OrderClose()

Синтаксис:

bool OrderClose( int ticket, double lots, double price, int slippage, color Color=CLR_NONE)

Описание:

Закрытие позиции. Возвращает TRUE при успешном завершении функции. Возвращает FALSE при неудачном завершении функции. Чтобы получить информацию об ошибке, необходимо вызвать функцию GetLastError().

Параметры:

ticket - Уникальный порядковый номер ордера.

lots - Количество лотов для закрытия.

price - Цена закрытия.

slippage - Значение максимального проскальзывания в пунктах.

Color - Цвет стрелки закрытия на графике. Если параметр отсутствует или его значение равно CLR_NONE, то стрелка на графике не отображается.

 

3 - OrderCloseBy()

Синтаксис:

bool OrderCloseBy( int ticket, int opposite, color Color=CLR_NONE)

Описание:

Закрытие одной открытой позиции другой позицией, открытой по тому же самому инструменту, но в противоположном направлении. Возвращает TRUE при успешном завершении функции. Возвращает FALSE при неудачном завершении функции. Чтобы получить информацию об ошибке, необходимо вызвать функцию GetLastError().

Параметры:

ticket - Уникальный порядковый номер закрываемого ордера.

opposite - Уникальный порядковый номер противоположного ордера.

Color - Цвет стрелки закрытия на графике. Если параметр отсутствует или его значение равно CLR_NONE, то стрелка на графике не отображается.

 

4 - OrderClosePrice()

Синтаксис:

double OrderClosePrice( )

Описание:

Возвращает цену закрытия выбранного ордера.

Ордер должен быть предварительно выбран с помощью функции OrderSelect().

Параметры:

- отсутствуют -

 

5 - OrderCloseTime()

Синтаксис:

datetime OrderCloseTime( )

Описание:

Возвращает время закрытия для выбранного ордера. Только закрытые ордера имеют время закрытия, не равное 0. Открытые или отложенные ордера имеют время закрытия, равное 0.

Ордер должен быть предварительно выбран с помощью функции OrderSelect().

Параметры:

- отсутствуют -

 

6 - OrderComment()

Синтаксис:

string OrderComment( )

Описание:

Возвращает комментарий для выбранного ордера.

Ордер должен быть предварительно выбран с помощью функции OrderSelect().

Параметры:

- отсутствуют -

 

7 - OrderCommission()

Синтаксис:

double OrderCommission( )

Описание:

Возвращает значение рассчитанной комиссии для выбранного ордера.

Ордер должен быть предварительно выбран с помощью функции OrderSelect().

Параметры:

- отсутствуют -

 

8 - OrderDelete()

Синтаксис:

bool OrderDelete( int ticket, color arrow_color=CLR_NONE)

Описание:

Удаляет ранее установленный отложенный ордер. Возвращает TRUE при успешном завершении функции. Возвращает FALSE при неудачном завершении функции. Чтобы получить информацию об ошибке, необходимо вызвать функцию GetLastError().

Параметры:

ticket - Уникальный порядковый номер ордера.

arrow_color - Цвет стрелки на графике. Если параметр отсутствует или его значение равно CLR_NONE, то стрелка на графике не отображаются.

 

9 - OrderExpiration()

Синтаксис:

datetime OrderExpiration( )

Описание:

Возвращает дату истечения для выбранного отложенного ордера.

Ордер должен быть предварительно выбран с помощью функции OrderSelect().

Параметры:

- отсутствуют -

 

10 - OrderLots()

Синтаксис:

double OrderLots( )

Описание:

Возвращает количество лотов для выбранного ордера.

Ордер должен быть предварительно выбран с помощью функции OrderSelect().

Параметры:

- отсутствуют -

 

11 - OrderMagicNumber()

Синтаксис:

int OrderMagicNumber( )

Описание:

Возвращает идентификационное ("магическое") число для выбранного ордера.

Ордер должен быть предварительно выбран с помощью функции OrderSelect().

Параметры:

- отсутствуют -

 

12 - OrderModify()

Синтаксис:

bool OrderModify( int ticket, double price, double stoploss, double takeprofit, datetime expiration, color arrow_color=CLR_NONE)

Описание:

Изменяет параметры ранее открытых позиций или отложенных ордеров. Возвращает TRUE при успешном завершении функции. Возвращает FALSE при неудачном завершении функции. Чтобы получить информацию об ошибке, необходимо вызвать функцию GetLastError().

Замечания: цену открытия и время истечения можно изменять только у отложенных ордеров.

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

На некоторых торговых серверах может быть установлен запрет на применение срока истечения отложенных ордеров. В этом случае при попытке задать ненулевое значение в параметре expiration будет сгенерирована ошибка 147 (ERR_TRADE_EXPIRATION_DENIED).

Параметры:

ticket - Уникальный порядковый номер ордера.

price - Новая цена открытия отложенного ордера.

stoploss - Новое значение StopLoss.

takeprofit - Новое значение TakeProfit.

expiration - Время истечения отложенного ордера.

arrow_color - Цвет стрелок модификации StopLoss и/или TakeProfit на графике. Если параметр отсутствует или его значение равно CLR_NONE, то стрелки на графике не отображаются.

 

13 - OrderOpenPrice()

Синтаксис:

double OrderOpenPrice( )

Описание:

Возвращает цену открытия для выбранного ордера.

Ордер должен быть предварительно выбран с помощью функции OrderSelect().

Параметры:

- отсутствуют -

 

14 - OrderOpenTime()

Синтаксис:

datetime OrderOpenTime( )

Описание:

Возвращает время открытия выбранного ордера.

Ордер должен быть предварительно выбран с помощью функции OrderSelect().

Параметры:

- отсутствуют -

 

(продолжение в след. посте)

post-50854-1404215535,4095_thumb.gif

Edited by Programmer

Share this post


Link to post
Share on other sites
Programmer

15 - OrderPrint()

Синтаксис:

void OrderPrint( )

Описание:

Выводит данные ордера в журнал в виде строки следующего формата:

номер тикета; время открытия; торговая операция; количество лотов; цена открытия; стоп лосс; тейк профит; время закрытия; цена закрытия; комиссия; своп; прибыль; комментарий; магическое число; дата истечения отложенного ордера.

Ордер должен быть предварительно выбран с помощью функции OrderSelect().

Параметры:

- отсутствуют -

 

16 - OrderProfit()

Синтаксис:

double OrderProfit( )

Описание:

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

Ордер должен быть предварительно выбран с помощью функции OrderSelect().

Параметры:

- отсутствуют -

 

17 - OrderSelect()

Синтаксис:

bool OrderSelect( int index, int select, int pool=MODE_TRADES)

Описание:

Функция выбирает ордер для дальнейшей работы с ним. Возвращает TRUE при успешном завершении функции. Возвращает FALSE при неудачном завершении функции. Чтобы получить информацию об ошибке, необходимо вызвать функцию GetLastError().

Параметр pool игнорируется, если ордер выбирается по номеру тикета. Номер тикета является уникальным идентификатором ордера. Чтобы определить, из какого списка выбран ордер, необходимо проанализировать его время закрытия. Если время закрытия ордера равно 0, то ордер является открытым или отложенным и взят из списка открытых позиций терминала. Отличить открытую позицию от отложенного ордера можно по типу ордера. Если время закрытия ордера не равно 0, то ордер является закрытым или удаленным отложенным и был выбран из истории терминала. Отличить закрытый ордер от удаленного отложенного также можно по типу ордера.

Параметры:

index - Позиция ордера или номер ордера в зависимости от второго параметра.

select - Флаг способа выбора. Mожет быть одним из следующих величин:

SELECT_BY_POS - в параметре index передается порядковый номер позиции в списке,

SELECT_BY_TICKET - в параметре index передается номер тикета.

pool - Источник данных для выбора. Используется, когда параметр select равен SELECT_BY_POS. Mожет быть одной из следующих величин:

MODE_TRADES (по умолчанию) - ордер выбирается среди открытых и отложенных ордеров,

MODE_HISTORY - ордер выбирается среди закрытых и удаленных ордеров.

 

18 - OrderHistoryTotal()

Синтаксис:

int OrdersHistoryTotal( )

Описание:

Возвращает количество закрытых позиций и удаленных ордеров в истории текущего счета, загруженной в клиентском терминале. Размер списка истории зависит от текущих настроек вкладки "История счета" терминала.

Параметры:

- отсутствуют -

 

19 - OrderStopLoss()

Синтаксис:

double OrderStopLoss( )

Описание:

Возвращает значение цены закрытия позиции при достижении уровня убыточности (stop loss) для текущего выбранного ордера.

Ордер должен быть предварительно выбран с помощью функции OrderSelect().

Параметры:

- отсутствуют -

 

20 - OrdersTotal()

Синтаксис:

int OrdersTotal( )

Описание:

Возвращает общее количество открытых и отложенных ордеров.

Параметры:

- отсутствуют -

 

21 - OrderSwap()

Синтаксис:

double OrderSwap( )

Описание:

Возвращает значение свопа для текущего выбранного ордера.

Ордер должен быть предварительно выбран с помощью функции OrderSelect().

Параметры:

- отсутствуют -

 

22 - OrderSymbol()

Синтаксис:

string OrderSymbol( )

Описание:

Возвращает наименование финансового инструмента для текущего выбранного ордера.

Ордер должен быть предварительно выбран с помощью функции OrderSelect().

Параметры:

- отсутствуют -

 

23 - OrderTakeProfit()

Синтаксис:

double OrderTakeProfit( )

Описание:

Возвращает значение цены закрытия позиции при достижении уровня прибыльности (take profit) для текущего выбранного ордера

Ордер должен быть предварительно выбран с помощью функции OrderSelect().

Параметры:

- отсутствуют -

 

24 - OrderTicket()

Синтаксис:

int OrderTicket( )

Описание:

Возвращает номер тикета для текущего выбранного ордера.

Ордер должен быть предварительно выбран с помощью функции OrderSelect().

Параметры:

- отсутствуют -

 

25 - OrderType()

Синтаксис:

int OrderType( )

Описание:

Возвращает тип операции текущего выбранного ордера. Mожет быть одной из следующих величин:

OP_BUY - позиция на покупку,

OP_SELL - позиция на продажу,

OP_BUYLIMIT - отложенный ордер на покупку по достижении заданного уровня, текущая цена выше уровня,

OP_BUYSTOP - отложенный ордер на покупку по достижении заданного уровня, текущая цена ниже уровня,

OP_SELLLIMIT - отложенный ордер на продажу по достижении заданного уровня, текущая цена ниже уровня,

OP_SELLSTOP - отложенный ордер на продажу по достижении заданного уровня, текущая цена выше уровня.

Ордер должен быть предварительно выбран с помощью функции OrderSelect().

Параметры:

- отсутствуют -

 

Замечания

Хотел бы, чтобы Вы обратили внимание на наиболее важные торговые функции:

OrderSend()

OrderModify()

OrderSelect()

OrderClose()

OrderDelete()

А на закуску мы рассмотрим ошибки исполнения:

Любая торговая операция (функции OrderSend(), OrderClose, OrderCloseBy, OrderDelete или OrderModify) по ряду причин может завершиться неудачей и вернуть либо отрицательный номер тикета, либо FALSE. Причину неудачи можно выяснить, вызвав функцию GetLastError(). Каждая ошибка должна быть обработана по-своему. Ниже в таблице приведены общие рекомендации.

Коды ошибок, возвращаемые торговым сервером:

 



 

© Kirill. [email protected]

post-50854-1404215535,4441_thumb.jpg

Edited by Programmer

Share this post


Link to post
Share on other sites
Programmer

Урок 16 - Ваш первый советник (часть 3)

 

Привет! Соскучились? Надеюсь, Вам хватило времени познакомиться с торговыми функциями MQL4, потому что сегодня они нам проигодятся.

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

Итак, начнём.

 

Код, который мы уже имеем:

 

//+------------------------------------------------------------------+
//|              My_First_EA.mq4 |
//|                 Kirill |
//|            [email="[email protected]"][email protected][/email] |
//+------------------------------------------------------------------+
#property copyright "Kirill"
#property link   "[email="[email protected]"][email protected][/email]"
//---- input parameters
extern double TakeProfit=350.0;
extern double Lots=0.1;
extern double TrailingStop=35.0;
//+------------------------------------------------------------------+
//| expert initialization function           |
//+------------------------------------------------------------------+
int init()
 {
//----

//----
  return(0);
 }
//+------------------------------------------------------------------+
//| expert deinitialization function         |
//+------------------------------------------------------------------+
int deinit()
 {
//----

//----
  return(0);
 }
int Crossed (double line1 , double line2)
{
  static int last_direction = 0;
  static int current_dirction = 0;
  if(line1>line2)current_dirction = 1; //up
  if(line1<line2)current_dirction = 2; //down
  if(current_dirction != last_direction) //changed
  {
  last_direction = current_dirction;
  return (last_direction);
  }
  else
  {
  return (0);
  }
}
//+------------------------------------------------------------------+
//| expert start function           |
//+------------------------------------------------------------------+
int start()
{
//----
  int cnt, ticket, total;
  double shortEma, longEma;
  if(Bars<100)
  {
  Print("bars less than 100");
  return(0);
  }
  if(TakeProfit<10)
  {
  Print("TakeProfit less than 10");
  return(0); // check TakeProfit
  }
  shortEma = iMA(NULL,0,8,0,MODE_EMA,PRICE_CLOSE,0);
  longEma = iMA(NULL,0,13,0,MODE_EMA,PRICE_CLOSE,0);
  int isCrossed = Crossed (shortEma,longEma);
  total = OrdersTotal();
  if(total < 1)
  {
  if(isCrossed == 1)
  {
  ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,0,Ask+TakeProfit*Point, "My EA",12345,0,Green);
  if(ticket>0)
  {
  if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
     Print("BUY order opened : ",OrderOpenPrice());
  }
  else Print("Error opening BUY order : ",GetLastError());
  return(0);
  }
  if(isCrossed == 2)
  {
  ticket=OrderSend(Symbol(),OP_SELL,Lots,Bid,3,0,
  Bid-TakeProfit*Point,"My EA",12345,0,Red);
  if(ticket>0)
  {
  if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
     Print("SELL order opened : ",OrderOpenPrice());
  }
  else Print("Error opening SELL order : ",GetLastError());
  return(0);
  }

  return(0);
  }
  for(cnt=0;cnt<total;cnt++)
  {
  OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
  if(OrderType()<=OP_SELL && OrderSymbol()==Symbol())
  {
  if(OrderType()==OP_BUY) // long position is opened
  {
  // should it be closed?
  if(isCrossed == 2)
  {
     OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet);   // close position
     return(0); // exit
  }

  // check for trailing stop
  if(TrailingStop>0)
  {
     if(Bid-OrderOpenPrice()>Point*TrailingStop)
     {
     if(OrderStopLoss()<Bid-Point*TrailingStop)
     {
     OrderModify(OrderTicket(),OrderOpenPrice(),Bid-Point*TrailingStop,OrderTakeProfit(),0,Green);
     return(0);
     }
     }
  }
  }

  else // go to short position
  {
  // should it be closed?
  if(isCrossed == 1)
  {
     OrderClose(OrderTicket(),OrderLots(),Ask,3,Violet);   // close position
     return(0); // exit
  }

  // check for trailing stop
  if(TrailingStop>0)
  {
     if((OrderOpenPrice()-Ask)>(Point*TrailingStop))
     {
     if((OrderStopLoss()>(Ask+Point*TrailingStop)) || (OrderStopLoss()==0))
     {
     OrderModify(OrderTicket(),OrderOpenPrice(),Ask+Point*TrailingStop,OrderTakeProfit(),0,Red);
     return(0);
     }
     }
  }
  }
  }
  }

  return(0);
}
//+------------------------------------------------------------------+

Последее, что мы разобрали в прошлый раз, - это функция Crossed(). Таким образом, мы подошли вплотную к функции start().

 

int cnt, ticket, total;

В этой строчке мы объявили три переменные типа integer. Мы смогли объявить все три переменные в одной строчке, потому что они все одинакого типа.

 

Замечание: Чтобы объявить несколько переменных в одной строчке, необходимо начать эту строчку с названия их типа, затем перечислить идентификаторы переменных через запятую.

С тем же успехом можно было разбить эту строчку на три части:

 

int cnt;
int ticket;
int total;

Переменную cnt мы будем использовать в качестве счётчика в нашем "цикле просмотра открытых позиций".

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

Переменную total мы будем использовать для хранения числа уже открытых ордеров.

 

double shortEma, longEma;

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

Мы будем использовать эти переменные для хранения значений быстрой EMA и медленной EMA.

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

 

   if(Bars<100)
  {
  Print("bars less than 100");
  return(0);
  }

Мы предполагаем, что график, с которым мы работаем, имеет больше 100 баров. Если это не так, то индикаторы EMA не смогут функционирывать.

Число баров на графике хранится в переменной Bars. С помощью этой переменной мы проверяем количество баров на графике в данный момент и, если оно меньше 100, мы сделаем 2 вещи: во-первых сообщим пользователю, напечатав в лог эксперта сообщение "bars less than 100", во-вторых мы завершим функцию start() оператором return(0);

Таким образом, мы отказываемся работать, если баров на графике меньше 100.

 

   if(TakeProfit<10)
  {
  Print("TakeProfit less than 10");
  return(0); // check TakeProfit
  }

Также мы не можем работать с неработоспособным значением параметра TakeProfit.

Переменная TakeProfit является внешней (extern), что означает, что пользователь может изменить её в окошке настроек советника.

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

Мы предполагаем, что любое значение меньше 10 для переменной TakeProfit является плохим выбором. Поэтому мы проверяем значение, заданное пользователем, и сравниваем его с 10. Если окажется, что значение меньше 10, мы сообщим об этом пользователю, распечатав сообщение "TakeProfit less than 10", и завершим функцию start() оператором return(0);

 

   shortEma = iMA(NULL,0,8,0,MODE_EMA,PRICE_CLOSE,0);
  longEma = iMA(NULL,0,13,0,MODE_EMA,PRICE_CLOSE,0);

Если всё в порядке: на графике больше 100 баров, и значение TakeProfit больше либо равно 10 - мы можем перейти к расчёту значений EMA на текущем баре.

Мы воспользуемся встроенным в MQL4 индикатором iMA, который рассчитает скользящие среднии.

Здесь нам придётся немного остановиться, чтобы поподробнее узнать о функции iMA.

 

iMA

 

Синтаксис:

double iMA( string symbol, int timeframe, int period, int ma_shift, int ma_method, int applied_price, int shift)

 

Описание:

Расчет скользящего среднего.

 

Параметры:

symbol - Символьное имя инструмента, на данных которого будет вычисляться индикатор. NULL означает текущий символ.

timeframe - Период. Может быть одним из периодов графика. 0 означает период текущего графика.

period - Период усреднения для вычисления скользящего среднего.

ma_shift - Сдвиг индикатора относительно ценового графика.

ma_method - Метод усреднения. Может быть любым из значений методов скользящего среднего (Moving Average).

applied_price - Используемая цена. Может быть любой из ценовых констант.

shift - Индекс получаемого значения из индикаторного буфера (сдвиг относительно текущего бара на указанное количество периодов назад).

 

Периоды графиков:



 

Методы скользящих:

 

Ценовые константы:

 

Всю эту информацию можно получить во встроенном справочнике MQL4. Достаточно лишь в окне Навигатор во вкладке Поиск набрать: iMA.

 

   shortEma = iMA(NULL,0,8,0,MODE_EMA,PRICE_CLOSE,0);
  longEma = iMA(NULL,0,13,0,MODE_EMA,PRICE_CLOSE,0);

Теперь Вы понимаете, что означают эти строчки.

Переменной shortEma мы присвоили значение, равное:

Усреднённую методом экспоненциального среднего цену Close последних 8 баров, начиная с текущего.

Коротко можно говорить EMA8.

Переменной longEma мы присвоили значение, равное:

Усреднённую методом экспоненциального среднего цену Close последних 13 баров, начиная с текущего.

Коротко можно говорить EMA13.

 

(продолжение в след. посте)

post-50854-1404215535,5922_thumb.gif

post-50854-1404215535,6198_thumb.gif

post-50854-1404215535,6402_thumb.gif

Edited by Programmer

Share this post


Link to post
Share on other sites
Programmer

int isCrossed = Crossed (shortEma,longEma);

 

Уверен, что Вы помните, что функция Crossed() принимает две переменные типа double и возвращает integer.

Первый параметр - это тек. значение первой линии, за которой мы хоти наблюдать. Второй - второй линии.

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

- Функция возвращает 0, если взаиморасположение линий не изменилось.

- Функция возвращает 1, если взаиморасположение линий изменилось, и первая линия оказалась над второй.

- Функция возвращает 2, если взаиморасположение линий изменилось, и первая линия оказалась под второй.

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

 

   total = OrdersTotal();
  if(total < 1)
  {
  ...
  }

 

Мы присвоили переменной total возвращаемое значение функции OrdersTotal().

 

Замечание: Функция OrdersTotal() возвращает общее количество открытых и ожидающих ордеров (см. урок 15).

Следующий за этим блок if сработает, только если нет ни одного открытого или ждущего ордера.

 

Блок if:

 

   {
  if(isCrossed == 1)
  {
  ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,0,Ask+TakeProfit*Point, "My EA",12345,0,Green);
  if(ticket>0)
  {
  if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
     Print("BUY order opened : ",OrderOpenPrice());
  }
  else Print("Error opening BUY order : ",GetLastError());
  return(0);
  }
  if(isCrossed == 2)
  {
  ticket=OrderSend(Symbol(),OP_SELL,Lots,Bid,3,0,Bid-TakeProfit*Point,"My EA",12345,0,Red);
  if(ticket>0)
  {
  if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
     Print("SELL order opened : ",OrderOpenPrice());
  }
  else Print("Error opening SELL order : ",GetLastError());
  return(0);
  }

 

В случае, когда EMA8 пересекла EMA13 снизу вверх, мы производим покупку. Для этого мы используем функцию OrderSend() (см. урок 15).

 

OrderSend()

 

Синтаксис:

int OrderSend( string symbol, int cmd, double volume, double price, int slippage, double stoploss, double takeprofit, string comment=NULL, int magic=0, datetime expiration=0, color arrow_color=CLR_NONE)

 

Параметры:

symbol

- Мы воспользовались функцией Symbol(), чтобы получить строку с названием валюты, и передали её (строку) функции OrderSend().

cmd

- Мы использовали OP_BUY, чтобы открыть сделку на покупку.

volume

- Мы использовали переменную Lots, значение которой нам предоставил пользователь.

price

- Мы воспользовались переменной (на самом деле функцией) Ask, чтобы получить тек. значение цены ask, и передали его функции OrderSend().

slippage

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

stoploss

- Мы использовали 0 в качествет стоп-лосса, что означает, что у этого ордера нет стоп-лосса.

takeprofit

- Мы воспользовались переменной TakeProfit, значение которой нам предоставил пользователь. Умножили её на цену одного пункта, хранящуюся в переменной Point, и прибавили результат к тек. значению Ask (цена открытия ордера). Это Важный момент обратите на него внимание. Аналогичным образом надо рассчитывать стоп-лосс, если он не равен нулю.

comment

- Мы использовали строку "My EA" в качестве комментария.

magic

- Мы испольлзовали число 12345 в качестве magic-числа. Магическое число нужно только для того, чтобы советник отличал свои ордера от чужих.

expiration

- Мы использовали 0, потому что нашему ордеру не нужен срок истечения. Этот параметр применим только к отложенным ордерам.

arrow_color

- Мы выбрали зелёный, потому что мы любим деньги, а деньги зелёные ;)

Функция OrderSend() при успешном исполнении возвращает тикет открытого ордера, что мы используем в проверке:

 

if(ticket>0)

 

Затем мы функцией OrderSelect() выбираем открытый ордер по его тикету, и функцией OrderOpenPrice() узнаём цену его открытия.

Если всё прошло успешно, и функция OrderSend() вернула нормальный тикет (больший 0), а функция OrderSelect() благополучно выбрала нужный ордер, то в лог эксперта распечатается сообщение "BUY order opened : " + цена открытия.

Для более подробной информации о OrderSelect() и OrderOpenPrice() см. урок 15.

Иначе, если функция OrderSend() вернула -1, что означает, что было ошибка, мы должны об этом сообщить пользователю, выдав сообщение: :Error opening BUY order: " + номер ошибки, предоставленный функцией GetLastError(). При этом нам придётся завершить функцию start() опреатором return(0);

 

   if(isCrossed == 2)
  {
  ticket=OrderSend(Symbol(),OP_SELL,Lots,Bid,3,0,
  Bid-TakeProfit*Point,"My EA",12345,0,Red);
  if(ticket>0)
  {
  if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
     Print("SELL order opened : ",OrderOpenPrice());
  }
  else Print("Error opening SELL order : ",GetLastError());
  return(0);
  }

 

Здесь сценарий противоположный - EMA8 пересекает EMA13 сверху вниз. Теперь мы продаём.

 

Можете найти различия в вызовах функции OrderSend() ?

Правильно!

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

symbol

volume

slippage

stoploss

comment

magic

expiration

 

А эти изменились:

cmd

- Мы использовали OP_SELL, чтобы открыть сделку на продажу.

price

- Мы воспользовались переменной (на самом деле функцией) Bid, чтобы получить тек. значение цены bid, и передали его функции OrderSend().

takeprofit

- Мы воспользовались переменной TakeProfit, значение которой нам предоставил пользователь. Умножили её на цену одного пункта, хранящуюся в переменной Point, и вычли результат к тек. значению Bid (цена открытия ордера).

arrow_color

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

Далее в этом куске кода всё аналогично.

Вот и всё... Мы закончили с блоком if(total<1). В следующ...

- Постой!

- Что?

- А я заметил ещё одну строчку в этом блоке, которую мы не разобрали!

- Где?

- Вот она:

 

   return(0);

 

- Отлично!

Посмотрите внимательно на эти строчки:

 

   if(total < 1)
  {
  if(isCrossed == 1)
  {
  ...
  }
  if(isCrossed == 2)
  {
  ...
  }

  return(0);   // <<-- Вот она
  }

 

Если EMA8 пересекает EMA13 снизу вверх, то мы покупаем.

Если EMA8 пересекает EMA13 сверху вниз, то мы продаём.

А что если они ещё не пересеклись? За это отвечает данная строчка. Она прервёт функцию start(), если ещё не было пересечения (в случае, если переменная isCrossed равна 1 или 2).

Теперь мы знаем, как наш советник открывает сделки. В последней части урока мы рассмотрим остаток кода и обсудим детали Тестера Стратегий MetaTrader.

Надеюсь, этот урок Вам понравился.

 

До встречи!

 

© Kirill. [email protected]

Share this post


Link to post
Share on other sites
Programmer

Урок 17 - Ваш первый советник (часть 4)

 

Мы дошли до края света в поисках истины! Нет, сегодня я не пил. Я просто счастлив, что наконец-то мы дошли до последней части серии уроков, посвящённых нашему первому эксперту!

 

Итак, начнём.

 

Код, который мы уже имеем:

 

//+------------------------------------------------------------------+
//|                                                  My_First_EA.mq4 |
//|                                                           Kirill |
//|                                          [email="[email protected]"][email protected][/email] |
//+------------------------------------------------------------------+
#property copyright "Kirill"
#property link      "[email="[email protected]"][email protected][/email]"
//---- input parameters
extern double    TakeProfit=350.0;
extern double    Lots=0.1;
extern double    TrailingStop=35.0;
//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
 {
//----

//----
  return(0);
 }
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
 {
//----

//----
  return(0);
 }
int Crossed (double line1 , double line2)
{
  static int last_direction = 0;
  static int current_dirction = 0;
  if(line1>line2)current_dirction = 1; //up
  if(line1<line2)current_dirction = 2; //down
  if(current_dirction != last_direction) //changed
  {
     last_direction = current_dirction;
     return (last_direction);
  }
  else
  {
     return (0);
  }
}
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
{
//----
  int cnt, ticket, total;
  double shortEma, longEma;
  if(Bars<100)
  {
     Print("bars less than 100");
     return(0);
  }
  if(TakeProfit<10)
  {
     Print("TakeProfit less than 10");
     return(0); // check TakeProfit
  }
  shortEma = iMA(NULL,0,8,0,MODE_EMA,PRICE_CLOSE,0);
  longEma = iMA(NULL,0,13,0,MODE_EMA,PRICE_CLOSE,0);
  int isCrossed = Crossed (shortEma,longEma);
  total = OrdersTotal();
  if(total < 1)
  {
     if(isCrossed == 1)
     {
        ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,0,Ask+TakeProfit*Point, "My EA",12345,0,Green);
        if(ticket>0)
        {
           if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
              Print("BUY order opened : ",OrderOpenPrice());
        }
        else Print("Error opening BUY order : ",GetLastError());
           return(0);
     }
     if(isCrossed == 2)
     {
        ticket=OrderSend(Symbol(),OP_SELL,Lots,Bid,3,0,
        Bid-TakeProfit*Point,"My EA",12345,0,Red);
        if(ticket>0)
        {
           if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
              Print("SELL order opened : ",OrderOpenPrice());
        }
        else Print("Error opening SELL order : ",GetLastError());
           return(0);
     }

  return(0);
  }
  for(cnt=0;cnt<total;cnt++)
  {
     OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
     if(OrderType()<=OP_SELL && OrderSymbol()==Symbol())
     {
        if(OrderType()==OP_BUY) // long position is opened
        {
        // should it be closed?
           if(isCrossed == 2)
           {
              OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet);   // close position
              return(0); // exit
           }

        // check for trailing stop
           if(TrailingStop>0)
           {
              if(Bid-OrderOpenPrice()>Point*TrailingStop)
              {
                 if(OrderStopLoss()<Bid-Point*TrailingStop)
                 {
                    OrderModify(OrderTicket(),OrderOpenPrice(),Bid-Point*TrailingStop,OrderTakeProfit(),0,Green);
                    return(0);
                 }
              }
           }
        }

        else // go to short position
        {
        // should it be closed?
           if(isCrossed == 1)
           {
              OrderClose(OrderTicket(),OrderLots(),Ask,3,Violet);   // close position
              return(0); // exit
           }

        // check for trailing stop
           if(TrailingStop>0)
           {
              if((OrderOpenPrice()-Ask)>(Point*TrailingStop))
              {
                 if((OrderStopLoss()>(Ask+Point*TrailingStop)) || (OrderStopLoss()==0))
                 {
                    OrderModify(OrderTicket(),OrderOpenPrice(),Ask+Point*TrailingStop,OrderTakeProfit(),0,Red);
                    return(0);
                 }
              }
           }
        }
     }
  }

  return(0);
}
//+------------------------------------------------------------------+

 

В предыдущем уроке мы разобрали, как происходит проверка того, что OrdersTotal меньше 1, для того, чтобы открывать сделку BUY или SELL только в случае, если до этого не было ни одной уже открытой сделки.

Мы исполльзовали след. код:

 

   if(total < 1)
  {
     if(isCrossed == 1)
     {
     ...
     }
     if(isCrossed == 2)
     {
     ...
     }

  return(0);
  }

 

Это был алгоритм открытия новых сделок. Сегодня мы изучим алгоритм закрытия и модификации уже открытых сделок.

 

   for(cnt=0;cnt<total;cnt++)
  {
  ...
  }

 

В вышеуказанном блоке мы используем цикл for для перебора всех открытых ордеров.

Мы начинаем цикл с cnt=0, потому что индексация (не тикеты, а именно их индексы в массиве, где они храняться) ордеров начинается с 0. На каждом щаге цикла мы увеличиваем cnt на 1 (cnt++).

Наша сегодняшняя задача заключается в изучении тела данного цикла.

 

      OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
     if(OrderType()<=OP_SELL && OrderSymbol()==Symbol())
     {
     ...
     }

 

Функция OrderSelect() используется для выбора открытого или отложенного ордера по его тикету или индексу. В этом цикле мы вызвали функцию OrderSelect() перед функциями OrderType() и OrderSymbol(), потому что если бы мы не вызвали её, то вторые две функции просто напросто не сработали бы.

 

Замечание: Функцию OrderSelect() необходимо вызывать перед следующими функциями, не принимающими никаких параметров:

 

OrderMagicNumber, OrderClosePrice, OrderCloseTime, OrderOpenPrice,

OrderOpenTime, OrderComment, OrderCommission, OrderExpiration, OrderLots,

OrderPrint, OrderProfit, OrderStopLoss, OrderSwap, OrderSymbol, OrderTakeProfit,

OrderTicket и OrderType

 

Мы использовали режим SELECT_BY_POS, что означает, что мы хотим выбрать ордер по его индексу, а не по его тикету.

 

Замечание: Индекс первого оредра: 0, второго: 1 и т.д.

 

(продолжение в след. посте)

  • Thanks 1
  • Downvote 1

Share this post


Link to post
Share on other sites
Programmer

Мы использовали режим MODE_TRADES, который означает, что мы будем выбирать ордер из открытых (или отложенных) на данный момент ордеров. Т.е. - не из истории.

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

OP_BUY, OP_SELL, OP_BUYLIMIT, OP_BUYSTOP, OP_SELLLIMIT или OP_SELLSTOP

Причём этими названиями закодированы обычные числа:

 



 

Мы проверяем, верно ли то, что тип выбранного ордера меньше либо равен значения OP_SELL. Это означает, что возможно лишь два варианта: OP_SELL и OP_BUY. Эта проверка необходима, т.к. мы не хотим трогать чужие отложенные ордра.

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

 

Так что весь последующий код будет работать только, если OrderType() равен OP_SELL или OP_BUY, а OrderSymbol() равен Symbol()

 

         if(OrderType()==OP_BUY) // long position is opened
        {
        ...
        }

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

Посмотрим, что же происходит дальше:

 

         // should it be closed?
           if(isCrossed == 2)
           {
              OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet);   // close position
              return(0); // exit
           }

Сделку на покупку мы открывали, когда быстрая EMA пересекала медленную EMA снизу вверх.

Логичным было бы закрывать эту сделку при обратном пересечении. Для этого мы вызываем функцию isCrossed(), и если она возвращает 2, то обратное пересечение произошло и необходимо закрыть сделку.

Для закрытия сделки мы используем функцию OrderClose(). Подробнее см. урок 15 - торговые функции.

 

Первым параметром она принимает значение тикета закрываемого ордера. Тикет мы предоставляем, используя функцию OrderTicket().

 

Вторым параметром функция принимает lots - количество лотов для закрытия (ВАЖНО: т.е. можно неполностью закрывать сделку). В нашем случае мы хотим закрыть весь ордер, поэтому в качестве lots предоставляем значение, возвращаемое функцией OrderLots().

 

Третим параметром функции OrderClose() является предпочитаемая цена закрытия. Ордер на покупку мы закрываем по тек. цене Bid.

 

Четвёртым параметром является slippage (допустимое проскальзывание цены исполнения). Здесь мы использовали значение 3.

 

Пятым параметром является цвет закрывающей стрелки. Мы использовали фиолетовый.

Затем мы не забыли завершить функцию start() оператором return(0);

 

         // check for trailing stop
           if(TrailingStop>0)
           {
              if(Bid-OrderOpenPrice()>Point*TrailingStop)
              {
                 if(OrderStopLoss()<Bid-Point*TrailingStop)
                 {
                    OrderModify(OrderTicket(),OrderOpenPrice(),Bid-Point*TrailingStop,OrderTakeProfit(),0,Green);
                    return(0);
                 }
              }
           }

Замечание: мы всё ещё находимся внутри блока if(OrderType()==OP_BUY)

 

В этом блоке кода мы применим технику треилинг-стопа к нашей открытой Buy позиции.

Для начала, мы проверяем, что предоставленное пользователем значение TrailingStop является пригодным (большим 0).

Затем мы проверяем, что:

 

1. Разница между тек. ценой Bid и ценой открытия сделки больше, чем величина TrailingStop. Это необходимо для того, чтобы треилинг стоп начинал работать толко при переносе стоп-лосса в безубыток. До этого момента стоп-лосс остаётся фиксированным.

 

2. Текущий стоп-лосс находится ниже, чем он должен быть. Т.е. ниже той цены, которую мы получим, если из тек. цены Bid вычтем величину TrailingStop.

Для осуществления необходимых модификаций мы применяем функцию OrderModify(). Подробнее см. урок 15 - торговые функции.

Её параметры следующие:

 

ticket: Тикет предоставляем с помощью функции OrderTicket().

 

price: У нас есть цена открытия ордера благодаря функции OrderOpenPrice().

 

stoploss: Вот то, что нам на самом деле нужно. Т.к. у нас сделка на покупку, то мы выставляем новый стоп-лосс на уровне, получаемом при вычитании из тек. цены Bid величины TrailingStop.

 

Замечание: Для сделки BUY стоп-лосс должен всегда находится НИЖЕ тек. цены bid. А для сделки SELL - ВЫШЕ тек. цены ask.

 

takeprofit: Без изменений. Тек. значение тейк-профита мы предоставляем функцией OrderTakeProfit().

 

expiration: Это не отложенный ордер у него нет срока истесения. Поэтому 0.

 

arrow_color: Оставляем зелёный цвет.

 

Наконец-то мы завершаем функцию start().

 

         else // go to short position
        {
        ...
        }

Этот блок выполняется в случае, если рассматриваемый ордер не на покупку, а на продажу. Строение и реализация этого блока (блока обработки ордера SELL) абсолютно аналогичны строению и реализации блоку обработки ордера BUY. Попробуйте разобраться с ним самостоятельно.

И в самом конце у нас есть строчка:

 

   return(0);

Эта строчка завершает функцию во всех остальных случаях: когда нет условий для открытия новых ордеров, нет условий для их закрытия или модификаций.

 

Надеюсь, вам понравился этот урок. Любые вопросы приветствуются.

До встречи на следующих уроках!

 

© Kirill. [email protected]

post-50854-1404215535,6619_thumb.gif

Edited by Programmer

Share this post


Link to post
Share on other sites
Programmer

Урок 18 - Ваш первый скрипт

 

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

 

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

Надеюсь, Вам понравилось это путешествие, и Вы готовы продолжать идти дальше по этой дороге вместе со мной.

 

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

 

Чего же мы ждём? Начнём!

 

Что такое скрипт?

 

Скрипт-язык - в Интернет - это интерпретируемый (объектно-ориентированный) алгоритмический язык, предназначенный для генерации динамических веб-страниц. Различают скрипт-языки:

- исполняемые на стороне клиента: JavaScript и VBScript; и

- исполняемые на стороне сервера: ASP, Perl, PHP и др.

 

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

 

MQL4 сам по себе является компилируемым языком. И файл *.ex4 - это скомпилированный и оптимизированный пи-код (по сути ассемблерные инструкции) для виртуальной машины MQL4.

 

Поэтому, в MQL4 под словом скрипт подразумевается совсем другое.

 

Что такое скрипт в MQL4?

 

Скрипт - это программа, которая исполняется единократно, сразу после чего завершается.

В отличие от экспертов, которые вызываются каждый раз, когда приходит новый тик, скрипты срабатывают только один раз.

И, в отличие от индикаторов, которые могут рисовать всякие линии на графике, скрипты не имеют доступа к индикаторным функциям.

Коротко - скрипт это советник, который срабатывает только раз.

Ну что? Создадим наш первый скрипт!

 

Опять помощник!

 

Помощника создаст за нас каркас программы.

Вызовите помощника: Файл -> Создать или нажав Ctrl+N. (рис. 1)

 

Мы создаём скрипт, поэтому выберите пункт "Пользовательский скрипт" и нажмите Далее.

 



рис. 1 - Помощник. Шаг 1.

 

После этого Вы окажетесь на втором шаге (рис. 2).

Заполните поля Название, Автор и Ссылка и нажмите Готово.

 



рис. 2 - Помощник. Шаг 2.

 

При нажатии кнопки готово Вы получите примерно такой код:

 

//+------------------------------------------------------------------+
//|                                              My_First_Script.mq4 |
//|                                                           Kirill |
//|                                          [email protected] |
//+------------------------------------------------------------------+
#property copyright "Kirill"
#property link      "[email protected]"

//+------------------------------------------------------------------+
//| script program start function                                    |
//+------------------------------------------------------------------+
int start()
 {
//----

//----
  return(0);
 }
//+------------------------------------------------------------------+

Замечание: Как Вы легко можете заметить из данного кода, помощник не создал функции init() и deinit(), а прописал только функцию start().

 

Это потому что очень сложно найти скрипт, которому нужно исполнять какой-либо код в функциях init() и deinit(), потому что сама функция start() будет выполнена лишь раз. Но это не значит, что функции init() и deinit() запрещены в скриптах. Вовсе нет - Вы можете их использовать, если хотите.

 

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

 

//+------------------------------------------------------------------+
//|                                              My_First_Script.mq4 |
//|                                                           Kirill |
//|                                          [email protected] |
//+------------------------------------------------------------------+
#property copyright "Kirill"
#property link      "[email protected]"

#property show_inputs

#include <stdlib.mqh>

extern double TakeProfit=250;
extern double StopLoss=35;

//+------------------------------------------------------------------+
//| script program start function                                    |
//+------------------------------------------------------------------+

int start()
{
//----

  int total,cnt,err;

  total = OrdersTotal();

  for(cnt=0;cnt<total;cnt++)
  {
     OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);

     if(OrderType()==OP_BUY) // long position is opened
     {
        OrderModify(OrderTicket(),OrderOpenPrice(),Bid-Point*StopLoss,Bid+Point*TakeProfit,0,Green);
        err=GetLastError();
        Print("error(",err,"): ",ErrorDescription(err));
        Sleep(1000);
     }

     if(OrderType()==OP_SELL) // short position is opened
     {
        OrderModify(OrderTicket(),OrderOpenPrice(),Ask+Point*StopLoss,Ask-Point*TakeProfit,0,Red);
        err=GetLastError();
        Print("error(",err,"): ",ErrorDescription(err));
        Sleep(1000);
     }
  }

//----

  return(0);
}

//+------------------------------------------------------------------+

Давайте разберём этот код построчно - как мы всегда это делаем.

 

//+------------------------------------------------------------------+
//|                                              My_First_Script.mq4 |
//|                                                           Kirill |
//|                                          [email protected] |
//+------------------------------------------------------------------+
#property copyright "Kirill"
#property link      "[email protected]"

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

Также были созданы две директивы #property.

 

#property show_inputs

Мы добавили директиву #property show_inputs в наш скрипт.

Без этой директивы скрипт не будет принимать входных данных от пользователя, а потому не появится окошко настроек скрипта, как указанное на рис. 3.

В нашем скрипте пользователь может задавать значения переменных TakeProfit и StopLoss в этом окошке. Или он может оставить значения по-умолчанию.

 

Замечание: Если Ваша задача написать скрипт, который не требует задания входных параметров пользователем, лучше убрать эту директиву.

 



Рис. 3 - Окошко настроек скрипта.

 

 

(продолжение в след. посте)

post-50854-1404215535,6881_thumb.gif

post-50854-1404215535,7153_thumb.gif

post-50854-1404215535,7377_thumb.gif

Edited by Programmer

Share this post


Link to post
Share on other sites
Guest
This topic is now closed to further replies.

  • Recently Browsing   0 members

    No registered users viewing this page.

×