Jump to content
Programmer

Курс MQL4

Recommended Posts

Programmer

11 - ObjectsDeleteAll( )

 

Синтаксис:

int ObjectsDeleteAll( int window=EMPTY, int type=EMPTY)

 

Описание:

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

Замечания: нумерация подокон графика (если на графике есть подокна с индикаторами) начинается с 1. Главное окно графика есть всегда и имеет индекс 0. Если индекс окна отсутствует или имеет значение -1, то объекты удаляются со всего графика.

Если значение параметра type равно -1 или этот параметр отсутствует, то удаляются все объекты из указанного подокна.

 

Параметры:

window - Необязательный параметр. Индекс окна, на котором будут удалены объекты. Должен быть большим или равным -1 (EMPTY, значение по умолчанию) и меньшим, чем WindowsTotal().

type - Необязательный параметр. Тип объекта для удаления. Это может быть любое из значений списка идентификаторов типов объектов или EMPTY (-1) для удаления всех объектов.

 

 

12 - ObjectSet()

 

Синтаксис:

bool ObjectSet( string name, int prop_id, double value)

 

Описание:

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

См. также ObjectGet().

 

Параметры:

name - Имя объекта.

prop_id - Идентификатор свойства объекта. Может быть любым из списка свойств объекта.

value - Новое значение указанного свойства.

 

 

13 - ObjectSetFiboDescription()

 

Синтаксис:

bool ObjectSetFiboDescription( string name, int index, string text)

 

Описание:

Функция присваивает новое описание уровню объекта Фибоначчи. Количество уровней зависит от типа объекта Фибоначчи. Максимальное количество уровней - 32.

Для получения информации об ошибке необходимо вызвать функцию GetLastError().

 

Параметры:

name - Имя объекта.

index - Порядковый номер уровня объекта Фибоначчи (0-31).

text - Новое описание уровня.

 

 

14 - ObjectSetText()

 

Синтаксис:

bool ObjectSetText( string name, string text, int font_size, string font_name=NULL, color text_color=CLR_NONE)

 

Описание:

Изменение описания объекта. Для объектов OBJ_TEXT и OBJ_LABEL это описание отображается на графике в виде текстовой строки. В случае успеха функция возвращает значение TRUE, иначе FALSE. Для получения дополнительной информации об ошибке необходимо вызвать функцию функцию GetLastError().

Параметры font_size, font_name и text_color используются только для объектов OBJ_TEXT и OBJ_LABEL. Для объектов других типов эти параметры игнорируются.

См. также ObjectDescription().

 

Параметры:

name - Имя объекта.

text - Текст описания обьекта.

font_size - Размер шрифта в пунктах.

font_name - Наименование шрифта.

text_color - Цвет текста.

 

 

15 - ObjectsTotal()

 

Синтаксис:

int ObjectsTotal( int type=EMPTY)

 

Описание:

Возвращает общее число объектов указанного типа на графике.

 

Параметры:

type - Необязательный параметр. Тип объекта для подсчета количества объектов данного типа. Это может быть любое из значений списка идентификаторов типов объектов или EMPTY (-1) для подсчета всех объектов.

 

 

16 - ObjectType()

 

Синтаксис:

int ObjectType( string name)

 

Описание:

Функция возвращает тип указанного объекта. Для получения информации об ошибке необходимо вызвать функцию GetLastError().

 

Параметры:

name - Имя объекта.

 

До следующего урока!

© Kirill. [email protected]

Share this post


Link to post
Share on other sites
Programmer

Урок 39 - Объекты (часть 3)

 

Всем привет!

Сегодня мы рассмотрим пример работы с объектами.

 

Код:

 

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

#property indicator_chart_window

int deinit()
{
  ObjectDelete("Obj001");
  ObjectDelete("Obj002");
  return(0);
}

int start()
{
  if(ObjectFind("Obj001")==-1)
  {
     ObjectCreate("Obj001", OBJ_TEXT, 0, Time[1], Close[1]);
     ObjectSetText("Obj001", "Hello world!", 25, "Times New Roman", Red);
  }

  if(ObjectFind("Obj002")==-1)
  {   
     ObjectCreate("Obj002", OBJ_TREND, 0, Time[100], Close[100], Time[1], Close[1]);
     ObjectSet("Obj002", OBJPROP_RAY, false);
     ObjectSet("Obj002", OBJPROP_COLOR, Blue);
     ObjectSet("Obj002", OBJPROP_WIDTH, 5);      
  }

  return(0);
}

Пояснения:

 

if(ObjectFind("Obj001")==-1)

Данное условие проверяет, что нет объекта с именем "Obj001". Мы это проверяем для того, чтобы ничего не делать, если объект уже есть.

 

      ObjectCreate("Obj001", OBJ_TEXT, 0, Time[1], Close[1]);
     ObjectSetText("Obj001", "Hello world!", 25, "Times New Roman", Red);

Создаём текстовый объект и меняем его параметры - текст, размер, шрифт, цвет.

 

if(ObjectFind("Obj002")==-1)

См. выше.

 

ObjectCreate("Obj002", OBJ_TREND, 0, Time[100], Close[100], Time[1], Close[1]);

Создаём трендовую линию с именем "Obj002".

 

ObjectSet("Obj002", OBJPROP_RAY, false);

Вот этот момент я специльно включил в урок! Меня часто спрашивают про это. Такой строчкой отключается параметр "луч" трендовой линии и она становится отрезком.

 

ObjectSet("Obj002", OBJPROP_COLOR, Blue);

Меняем цвет.

 

ObjectSet("Obj002", OBJPROP_WIDTH, 5);

Меняем ширину.

 

int deinit()
{
  ObjectDelete("Obj001");
  ObjectDelete("Obj002");
  return(0);
}

И наконец, в функции deinit мы удаляем все объекты, которые создал индикатор. Это позволяет очистить график при удалении с него индикатора.

 

Если Вы всё правильно сделали, то при запуске индикатора на графике Вы должны увидеть следующее:

 



Рис.1 - Результат.

 

До встречи на следующем уроке!

© Kirill. [email protected]

post-50854-1404215004,2066_thumb.gif

Share this post


Link to post
Share on other sites
Programmer

Урок 40 - Метки (часть 1)

 

Всем привет!

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

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

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

 

Поехали!

 

Что такое Метки (Labels)?

Метки - это графические текстовые объекты, жёстко привязанные к относительным координатам в каком-либо окне. Это означает, что метки как-бы не замечают грфик - они позиционированы относительно самого окна. В MQL4 метки называются OBJ_LABEL. Помните, как в прошлом уроке мы создавали текстовый объект "Hello World!"? Тот текст был просто текстом типа OBJ_TEXT и его расположение на графике задавалось двумя абсолютными координатамя - временем и ценой. Это означает, что тот текст будет перемещаться вместе с графиком влево по мере поступления новых баров.

 

Как создать метку вручную?

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

 



Рис. 1 - Выбор объекта "Text Label"

 

 

Рис. 2 - Задание текста метки

 

 

Рис. 3 - Выбор расположения метки

 

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

В данном примере метка привязана к верхнему правому углу с отуступом 40px по горизонтали и 15px по вертикали.

Теперь, если я буду прокручивать график, метка будет оставаться на месте. См. рис. 4.

 



Рис. 4 - Метка неподвижна относительно окна графика

 

Надеюсь, вы узнали что-то новое для себя!

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

 

До встречи на следующем уроке!

© Kirill. [email protected]

post-50854-1404215039,7651_thumb.gif

post-50854-1404215039,8399_thumb.gif

post-50854-1404215039,9111_thumb.gif

post-50854-1404215040,057_thumb.gif

Share this post


Link to post
Share on other sites
Programmer

Урок 41 - Метки (часть 2)

 

Привествую всех!

Сегодня мы узнаем, как работать с метками с точки зрения MQL4.

Прежде всего скажу, что программирование меток немного отличается от программирования других объектов MQL4, и сейчас мы увидим - почему.

 

Код:

 

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


int start()
{
  ObjectCreate("label_top_right", OBJ_LABEL, 0, 0, 0);

  ObjectSetText("label_top_right", "TOP RIGHT", 14, "Arial", Aqua);

  ObjectSet("label_top_right", OBJPROP_CORNER, 1);
  ObjectSet("label_top_right", OBJPROP_XDISTANCE, 100);
  ObjectSet("label_top_right", OBJPROP_YDISTANCE, 100);
}

Это совсем простенький скрипт. Давайте его разберём.

 

ObjectCreate("label_top_right", OBJ_LABEL, 0, 0, 0);

Данной строчкой мы создаём объект типа OBJ_LABEL под названием "label_top_right". Первый нуль означает, что мы хотим поместить объект в главное окошко графика. А вот вторые два - это специфика создания меток. Поскольку метка использует пиксельные координаты, чтобы узнать своё расположение на графике, ей не нужны обычные координаты (время и цена), передаваемые через функцию ObjectCreate(). Эти две координаты игнорируются, поэтому мы просто передаём туда нули.

 

Метка использует свои особые параметры, а именно:

OBJPROP_CORNER - Получает/устанавливает номер угла привязки для объекта OBJ_LABEL. Принимает значения 0-3

OBJPROP_XDISTANCE - Получает/устанавливает расстояние X-координаты в пикселях относительно угла привязки для объекта OBJ_LABEL

OBJPROP_YDISTANCE - Получает/устанавливает расстояние Y-координаты в пикселях относительно угла привязки для объекта OBJ_LABEL

Эти параметры мы увидим после следующей строчки:

 

ObjectSetText("label_top_right", "TOP RIGHT", 14, "Arial", Aqua);

Здесь мы задаём текст метки, размер шрифта, сам шрифт и цвет. Это аналог вкладки "Common" при ручном создании метки (см. пред. урок).

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

 

ObjectSet("label_top_right", OBJPROP_CORNER, 1);

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

 



Рис. 1 - Нумерация углов

 

 

ObjectSet("label_top_right", OBJPROP_XDISTANCE, 100);
ObjectSet("label_top_right", OBJPROP_YDISTANCE, 100);

Эти две строчки задают отступу (в пикселях) от угла по горизонтали и по вертикали соответственно. Это аналог вкладки "Parameters" при ручном создании метки (см. пред. урок).

Всё готово! Теперь цепляем скрипт на график, и вуаля!

 



Рис. 2 - Результат выполнения скрипта

 

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

 

До встречи на следующем уроке!

© Kirill. [email protected]

post-50854-1404215052,1316_thumb.gif

post-50854-1404215052,1992_thumb.gif

Share this post


Link to post
Share on other sites
Programmer

Урок 42 - Комплексный пример работы с объектами

 

Всем привет!

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

 

Сначала скажу немного о самом советнике.

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

 

Вот такой забавный советник!

 

Код:

 

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


extern int MagicNumber = 3;
extern double Lots = 0.1;
extern int StopLoss = 50;
extern int TakeProfit = 50;

double RedLine = 0;
double BlueLine = 0;

int init()
{
  Init_Red_Line();
  Init_Blue_Line();
  Init_Labels();

  return(0);
}

int deinit()
{
  Deinit_All_Objects();

  return(0);   
}

int start()
{
  Read_Red_Line();
  Read_Blue_Line();
  Check_Sell();
  Check_Buy();
  Update_Labels();

  return(0);
}

void Init_Red_Line()
{
  ObjectCreate("RedLine", OBJ_HLINE, 0, 0, Bid - 50*Point);
  ObjectSet("RedLine", OBJPROP_COLOR, Red);
  ObjectSet("RedLine", OBJPROP_WIDTH, 3);   
}

void Init_Blue_Line()
{
  ObjectCreate("BlueLine", OBJ_HLINE, 0, 0, Ask + 50*Point);
  ObjectSet("BlueLine", OBJPROP_COLOR, Blue);
  ObjectSet("BlueLine", OBJPROP_WIDTH, 3);   
} 

void Init_Labels()
{
  ObjectCreate("Label_Red1", OBJ_LABEL, 0, 0, 0);
  ObjectSetText("Label_Red1", "Initialization", 14, "Arial", Magenta);
  ObjectSet("Label_Red1", OBJPROP_CORNER, 1);
  ObjectSet("Label_Red1", OBJPROP_XDISTANCE, 15);
  ObjectSet("Label_Red1", OBJPROP_YDISTANCE, 30);

  ObjectCreate("Label_Blue1", OBJ_LABEL, 0, 0, 0);
  ObjectSetText("Label_Blue1", "Initialization", 14, "Arial", Aqua);
  ObjectSet("Label_Blue1", OBJPROP_CORNER, 1);
  ObjectSet("Label_Blue1", OBJPROP_XDISTANCE, 15);
  ObjectSet("Label_Blue1", OBJPROP_YDISTANCE, 15);

  ObjectCreate("Label_Red2", OBJ_LABEL, 0, 0, 0);
  ObjectSetText("Label_Red2", "Initialization", 14, "Arial", Magenta);
  ObjectSet("Label_Red2", OBJPROP_CORNER, 1);
  ObjectSet("Label_Red2", OBJPROP_XDISTANCE, 15);
  ObjectSet("Label_Red2", OBJPROP_YDISTANCE, 60);

  ObjectCreate("Label_Blue2", OBJ_LABEL, 0, 0, 0);
  ObjectSetText("Label_Blue2", "Initialization", 14, "Arial", Aqua);
  ObjectSet("Label_Blue2", OBJPROP_CORNER, 1);
  ObjectSet("Label_Blue2", OBJPROP_XDISTANCE, 15);
  ObjectSet("Label_Blue2", OBJPROP_YDISTANCE, 45);      
}

void Deinit_All_Objects()
{
  ObjectDelete("RedLine");
  ObjectDelete("BlueLine");
  ObjectDelete("Label_Red1");
  ObjectDelete("Label_Red2");
  ObjectDelete("Label_Blue1");
  ObjectDelete("Label_Blue2");
}

void Read_Red_Line()
{
  RedLine = ObjectGet("RedLine", OBJPROP_PRICE1);
}

void Read_Blue_Line()
{
  BlueLine = ObjectGet("BlueLine", OBJPROP_PRICE1);
}

void Check_Sell()
{
  static double LastBid = 10000;
  for(int i=OrdersTotal()-1; i>=0; i--)
  {
     OrderSelect(i, SELECT_BY_POS);
     if(OrderMagicNumber()==MagicNumber && OrderType()==OP_SELL)
        break;
  }
  if(i==-1)
  {
     if(LastBid>RedLine && Bid<RedLine)
        OrderSend(Symbol(), OP_SELL, Lots, Bid, 3, Bid+StopLoss*Point, Bid-TakeProfit*Point, "Objects_EA", MagicNumber); 
  }
  LastBid = Bid;
}

void Check_Buy()
{
  static double LastAsk = 0;
  for(int i=OrdersTotal()-1; i>=0; i--)
  {
     OrderSelect(i, SELECT_BY_POS);
     if(OrderMagicNumber()==MagicNumber && OrderType()==OP_BUY)
        break;
  }
  if(i==-1)
  {
     if(LastAsk<BlueLine && Ask>BlueLine)
        OrderSend(Symbol(), OP_BUY, Lots, Ask, 3, Ask-StopLoss*Point, Ask+TakeProfit*Point, "Objects_EA", MagicNumber); 
  }
  LastAsk = Ask;
}

void Update_Labels()
{
  ObjectSetText("Label_Red1", "RedLine set at: "+DoubleToStr(RedLine, Digits), 14, "Arial", Magenta);
  ObjectSetText("Label_Blue1", "BlueLine set at: "+DoubleToStr(BlueLine, Digits), 14, "Arial", Aqua);

  for(int i=OrdersTotal()-1; i>=0; i--)
  {
     OrderSelect(i, SELECT_BY_POS);
     if(OrderMagicNumber()==MagicNumber && OrderType()==OP_SELL)
        break;
  }
  if(i!=-1)
  {
     ObjectSetText("Label_Red2", "Sell Order: Exists", 14, "Arial", Magenta);
  }
  else
  {
     ObjectSetText("Label_Red2", "Sell Order: Not Found", 14, "Arial", Magenta);
  }   

  for(i=OrdersTotal()-1; i>=0; i--)
  {
     OrderSelect(i, SELECT_BY_POS);
     if(OrderMagicNumber()==MagicNumber && OrderType()==OP_BUY)
        break;
  }
  if(i!=-1)
  {
     ObjectSetText("Label_Blue2", "Buy Order: Exists", 14, "Arial", Aqua);
  }
  else
  {
     ObjectSetText("Label_Blue2", "Buy Order: Not Found", 14, "Arial", Aqua);
  }   
}

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

 

Итак.

 

int init()
{
  Init_Red_Line();
  Init_Blue_Line();
  Init_Labels();

  return(0);
}

Функция Init_Red_Line() - подготавливает красную линию.

Функция Init_Blue_Line() - подготавливает синюю линию.

Функция Init_Labels() - подготавливает метки. Меток всего 4: состояние синей линии, красной линии, был ли найден ордер на покупку, был ли найден ордер на продажу.

 

 

int deinit()
{
  Deinit_All_Objects();

  return(0);   
}

Функция Deinit_All_Objects() - удаляет с графика все объекты, созданные советником.

 

 

int start()
{
  Read_Red_Line();
  Read_Blue_Line();
  Check_Sell();
  Check_Buy();
  Update_Labels();

  return(0);
}

Функция Read_Red_Line() - считывает значение красной линии. Если Вы её перетащили мышкой, значит Вы хотите, чтобы ордер SELL был открыт при пробитии нового уровня, и советник должен считать значение этого уровня.

Функция Read_Blue_Line() - аналогично.

Функция Check_Sell() - данная ф-я производит попытку открыть ордер SELL. Необходимые условия: не должно быть уже открытого ордера SELL у данного советника И красная линия должна была быть только что пробита ценой сверху вниз.

Функция Check_Buy() - аналогично.

Функция Update_Labels() - обновляет метки.

 

 

Советник получился очень интересный!

Он отлично работает и открывает ордера точно так, как описано в алгоритме.

С ним интересно поиграться - например, на тестере стратегий в визуальном режиме.

Ниже - несколько скриншотов:

 



Рис. 1 - Пример работы советника

 

 

Рис. 2 - Пример работы советника

 

 

Рис. 3 - Пример работы советника

 

 

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

Уверен, что Вы сегодня узнали много нового!

 

До встречи на следующем уроке!

© Kirill. [email protected]

 

ВАЖНО: Код советника выкладывается исключительно в образовательных целях. Использование его на любых счетах - на свой страх и риск.

post-50854-1404215089,8838_thumb.gif

post-50854-1404215089,9343_thumb.gif

post-50854-1404215089,9867_thumb.gif

Share this post


Link to post
Share on other sites
Programmer

Урок 43 - Комплексный пример работы с объектами, разбор Часть 1

 

Всем привет!

С момента выхода последнего урока я получил рекордное количество вопросов на тему устройства кода советника из урока №42.

Тем, кто писал, хочу сказать, что большинство из Вас, в целом, на правильном пути, но есть пробелы. Например, многим надо повторить урок "№7 - Функции", многим ещё предстоит разобраться с метками, и т.д.

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

Начнём мы с алгоритма, который представлен нижеприведённой схемой:

 



Рис. 1 - Алгоритм

 

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

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

 

 

© Kirill. [email protected]

post-50854-1404215207,0339_thumb.png

  • Thanks 1

Share this post


Link to post
Share on other sites
Programmer

Урок 44 - Комплексный пример работы с объектами, разбор Часть 2

 

Всем привет!

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

 

Итак, поехали!

 

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

Здесь прописаны авторские права и заголовочный комментарий советника. Всё это за Вас создаёт мастер создания MQL4-программ.

 

 

extern int MagicNumber = 3;
extern double Lots = 0.1;
extern int StopLoss = 50;
extern int TakeProfit = 50;

Это инициализация внешних переменных. Эти переменные пользователь может менять в настройках советника.

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

Lots - торгуемый лот

StopLoss - стоп лосс в пунктах

TakeProfit - тейк профит в пунктах

 

 

double RedLine = 0;
double BlueLine = 0;

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

 

 

int init()
{
  Init_Red_Line();
  Init_Blue_Line();
  Init_Labels();

  return(0);
}

int deinit()
{
  Deinit_All_Objects();

  return(0);   
}

int start()
{
  Read_Red_Line();
  Read_Blue_Line();
  Check_Sell();
  Check_Buy();
  Update_Labels();

  return(0);
}

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

 

 

void Init_Red_Line()
{
  ObjectCreate("RedLine", OBJ_HLINE, 0, 0, Bid - 50*Point);
  ObjectSet("RedLine", OBJPROP_COLOR, Red);
  ObjectSet("RedLine", OBJPROP_WIDTH, 3);   
}

Эта функция инициализирует красную линию.

Первая строчка создаёт линию.

Вторая строчка задаёт ей красный цвет.

Третья строчка задаёт ей шиирину 3.

 

 

void Init_Blue_Line()
{
  ObjectCreate("BlueLine", OBJ_HLINE, 0, 0, Ask + 50*Point);
  ObjectSet("BlueLine", OBJPROP_COLOR, Blue);
  ObjectSet("BlueLine", OBJPROP_WIDTH, 3);   
} 

По аналогии.

 

 

void Init_Labels()
{
  ...
}

Данная функция инициализирует 4 метк (сверзу внизу): уровень синей линии, уровень красной линии, найден ли ордер на покупку, найден ли ордер на продажу.

Рассмотрим одну из таких инициализаций:

 

   ObjectCreate("Label_Red1", OBJ_LABEL, 0, 0, 0);
  ObjectSetText("Label_Red1", "Initialization", 14, "Arial", Magenta);
  ObjectSet("Label_Red1", OBJPROP_CORNER, 1);
  ObjectSet("Label_Red1", OBJPROP_XDISTANCE, 15);
  ObjectSet("Label_Red1", OBJPROP_YDISTANCE, 30);

Первая строчка создаёт метку с именем Label_Red1.

Вторая строчка задаёт её текстовое значение, размер шрифта, шрифт и его цвет. Помните, если не задать сам шрифт, то переметры размер и цвет не будут обработаны компилятором. Изначально мы во все метки вписываем строчку "Initailization" - потом поменяем.

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

Четвёртая строчка задаёт расстояние до угла по горизонтальной оси.

Пятая строчка задаёт расстояние до угла по вертикальной оси.

 

Остальные три метки сделаны по аналогии.

 

 

void Deinit_All_Objects()
{
  ObjectDelete("RedLine");
  ObjectDelete("BlueLine");
  ObjectDelete("Label_Red1");
  ObjectDelete("Label_Red2");
  ObjectDelete("Label_Blue1");
  ObjectDelete("Label_Blue2");
}

Данная функция просто удаляет все метки по их именам.

 

 

void Read_Red_Line()
{
  RedLine = ObjectGet("RedLine", OBJPROP_PRICE1);
}

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

 

 

void Read_Blue_Line()
{
  BlueLine = ObjectGet("BlueLine", OBJPROP_PRICE1);
}

По аналогии.

 

 

void Check_Sell()
{
  ...
}

Данная функция проверяет надо ли отправлять ордер на продажу, и если надо - отрпавляет его.

Рассмотрим её код подробней:

 

   static double LastBid = 10000;

Объявляем статичную переменную, в которой будем хранить значение предыдущего Bid для сравнения с текущим. Изначально делаем её большой, поскольку этого требует алгоритм для корректной работы на самом первом шаге.

 

   for(int i=OrdersTotal()-1; i>=0; i--)
  {
     OrderSelect(i, SELECT_BY_POS);
     if(OrderMagicNumber()==MagicNumber && OrderType()==OP_SELL)
        break;
  }

Цикл перебора по открытым ордерам(*). Как только находим ордер на продажу с нашим Magic, мы прерываем цикл перебора.

 

   if(i==-1)
  {
     if(LastBid>RedLine && Bid<RedLine)
        OrderSend(Symbol(), OP_SELL, Lots, Bid, 3, Bid+StopLoss*Point, Bid-TakeProfit*Point, "Objects_EA", MagicNumber); 
  }

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

 

   LastBid = Bid;

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

 

 

void Update_Labels()
{

}

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

 

   ObjectSetText("Label_Red1", "RedLine set at: "+DoubleToStr(RedLine, Digits), 14, "Arial", Magenta);

Текст красной метки один состоит из двух частей: "RedLine set at: " и самого значения уровня красной линии, которое мы переводим из числа в строку посредством функции DoubleToStr().

 

   ObjectSetText("Label_Blue1", "BlueLine set at: "+DoubleToStr(BlueLine, Digits), 14, "Arial", Aqua);

По аналогии.

 

   for(int i=OrdersTotal()-1; i>=0; i--)
  {
     OrderSelect(i, SELECT_BY_POS);
     if(OrderMagicNumber()==MagicNumber && OrderType()==OP_SELL)
        break;
  }
  if(i!=-1)
  {
     ObjectSetText("Label_Red2", "Sell Order: Exists", 14, "Arial", Magenta);
  }
  else
  {
     ObjectSetText("Label_Red2", "Sell Order: Not Found", 14, "Arial", Magenta);
  }   

Эта часть отвечает за текстк красной метки два. Здесь Вы видите точно такой же цикл перебора по открытым ордерам, что и (*). В случае, если ордер на продажу найден, метка принимает значение "Sell Order: Exists", если не найден - "Sell Order: Not Found".

 

   for(i=OrdersTotal()-1; i>=0; i--)
  {
     OrderSelect(i, SELECT_BY_POS);
     if(OrderMagicNumber()==MagicNumber && OrderType()==OP_BUY)
        break;
  }
  if(i!=-1)
  {
     ObjectSetText("Label_Blue2", "Buy Order: Exists", 14, "Arial", Aqua);
  }
  else
  {
     ObjectSetText("Label_Blue2", "Buy Order: Not Found", 14, "Arial", Aqua);
  }

По аналогии.

 

© Kirill. [email protected]

Share this post


Link to post
Share on other sites
Programmer

Урок 45 - Функции преобразования

 

Приветствую читателей курса по програмированию!

В предыдущем уроке мы затронули функцию DoubleToStr(). Эта функция является встроенной функцией для преобразования переменных типа Double в тип String. Сегодня мы разберёмся со всеми функциями преобразования в MQL4 раз и навсегда.

 

Зачем нужны функции преобразования?

Во многих ситуациях у Вас есть переменная в каком-то одном формате, а Вам она нужна в совершенно другом формате. Здесь члово "формат" подразумевает значение "тип".

Яркий пример: функция TimeCurrent() возвращает время в в datetime формате. Данный формат удобен для математичских и булевых операций - например, прибавить 2 часа. Но он совершенно не подходит для вывода на экран. Например, если передать переменную тип datetime в функцию Alert(), то распечатается оченрь большое число, которое на глаз не воспринимается, как время. Поэтому, перед печатью переменную datetime необходимо сконвертировать в тип string с помощью функции TimeToStr().

 

 

Неявная конвертация

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

 

Например:

 

string var1 = 100;
Alert(var1);

В данном примере Вы присвоили значение integer переменной типа string. MQL4 автоматически преобразует число 100 из integer в string.

 

Alert(var1+10);

Как Вы думаете, что получится? Нет, Вы НЕ получите 110 - Вы получите 10010 (см. рис. 1). Всё потому что, MQL4 преобразовал число 100 в строку "100" и число 10 в строку "10" и потом сложил их как строки.

 



Рис. 1 - Вывод на экран

 

 

А теперь изучим функции конвертации MQL4!

 

 

1 - CharToStr()

 

Синтаксис:

string CharToStr( int char_code)

 

Описание:

Преобразование кода символа в односимвольную строку.

 

Параметры:

char_code - ASCII-код символа.

 

 

2 - DoubleToStr()

 

Синтаксис:

string DoubleToStr( double value, int digits)

 

Описание:

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

 

Параметры:

value - Величина с плавающей точкой.

digits - Формат точности, число цифр после десятичной точки (0-8).

 

 

3 - NormalizeDouble()

 

Синтаксис:

double NormalizeDouble( double value, int digits)

 

Описание:

Округление числа с плавающей запятой до указанной точности.

Рассчитываемые значения StopLoss, TakeProfit, а также значения цены открытия отложенных ордеров должны быть нормализованы с точностью, значение которой хранится в предопределенной переменной Digits.

 

Параметры:

value - Величина с плавающей точкой.

digits - Формат точности, число цифр после десятичной точки (0-8).

 

 

4 - StrToDouble()

 

Синтаксис:

double StrToDouble( string value))

 

Описание:

Преобразование строки, содержащей символьное представление числа, в число типа double (формат двойной точности с плавающей точкой).

 

Параметры:

value - Строка, содержащая символьное представление числа.

 

 

5 - StrToInteger()

 

Синтаксис:

int StrToInteger( string value)

 

Описание:

Преобразование строки, содержащей символьное представление числа, в число типа int (целое).

 

Параметры:

value - Строка, содержащая число.

 

 

6 - StrToTime()

 

Синтаксис:

datetime StrToTime( string value)

 

Описание:

Преобразование строки, содержащей время и/или дату в формате "yyyy.mm.dd [hh:mi]", в число типа datetime (количество секунд, прошедших с 01.01.1970).

 

Параметры:

value - Строка в формате "yyyy.mm.dd hh:mi".

 

 

7 - TimeToStr()

 

Синтаксис:

string TimeToStr( datetime value, int mode=TIME_DATE|TIME_MINUTES)

 

Описание:

Преобразование значения, содержащего время в секундах, прошедшее с 01.01.1970, в строку формата "yyyy.mm.dd hh:mi".

 

Параметры:

value - Время в секундах от 00:00 1 января 1970.

mode - Дополнительный режим вывода данных. Может быть одним или комбинированным флагом:

TIME_DATE получает результат в форме "yyyy.mm.dd",

TIME_MINUTES получает результат в форме "hh:mi",

TIME_SECONDS получает результат в форме "hh:mi:ss".

 

 

Надеюсь, данный урок был Вам полезен.

До встречи на следующем уроке!

 

© Kirill. [email protected]

post-50854-1404215248,8548_thumb.gif

Share this post


Link to post
Share on other sites
Programmer

Урок 46 - Функции доступа к таймсериям

 

Приветствую всех!

Я часто слышу вопрос: "Может ли советник работать сразу на двух графиках?" и "Может ли советник анализировать данные с таймфреймов, отличных от того, на котором он запущен?" И ответ на подобные вопросы: "Да!" Для того, чтобы это программировать надо всего лишь научиться использовать функции доступа к таймсериям, которые мы изучим сегодня.

Поехали!

 

1 - iBars()

 

Синтаксис:

int iBars( string symbol, int timeframe)

 

Описание:

Возвращает количество баров на определенном графике.

Для текущего графика информация о количестве баров находится в предопределенной переменной Bars.

 

Параметры:

symbol - Символьное имя инструмента. NULL означает текущий символ.

timeframe - Период. Может быть одним из периодов графика. 0 означает период текущего графика.

 

 

2 - iBarShift()

 

Синтаксис:

int iBarShift( string symbol, int timeframe, datetime time, bool exact=false)

 

Описание:

Поиск бара по времени. Функция возвращает смещение бара, которому принадлежит указанное время. Если для указанного времени бар отсутствует ("дыра" в истории), то функция возвращает, в зависимости от параметра exact, -1 или смещение ближайшего бара.

 

Параметры:

symbol - Символьное имя инструмента. NULL означает текущий символ.

timeframe - Период. Может быть одним из периодов графика. 0 означает период текущего графика.

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

exact - Возвращаемое значение если бар не найден. FALSE - iBarShift возвращает ближайший. TRUE - iBarShift возвращает -1.

 

 

3 - iClose()

 

Синтаксис:

double iClose( string symbol, int timeframe, int shift)

 

Описание:

Возвращает значение цены закрытия указанного параметром shift бара с соответствующего графика (symbol, timeframe). В случае ошибки функция возвращает 0. Для получения дополнительной информации об ошибке необходимо вызвать функцию GetLastError().

Для текущего графика информация о ценах закрытия находится в предопределенном массиве Close[].

 

Параметры:

symbol - Символьное имя инструмента. NULL означает текущий символ.

timeframe - Период. Может быть одним из периодов графика. 0 означает период текущего графика.

shift - Индекс получаемого значения из таймсерии (сдвиг относительно текущего бара на указанное количество периодов назад).

 

 

4 - iHigh()

 

Синтаксис:

double iHigh( string symbol, int timeframe, int shift)

 

Описание:

Возвращает значение максимальной цены указанного параметром shift бара с соответствующего графика (symbol, timeframe). В случае ошибки функция возвращает 0. Для получения дополнительной информации об ошибке необходимо вызвать функцию GetLastError().

Для текущего графика информация о максимальных ценах находится в предопределенном массиве High[].

 

Параметры:

symbol - Символьное имя инструмента. NULL означает текущий символ.

timeframe - Период. Может быть одним из периодов графика. 0 означает период текущего графика.

shift - Индекс получаемого значения из таймсерии (сдвиг относительно текущего бара на указанное количество периодов назад).

 

 

5 - iHighest()

 

Синтаксис:

int iHighest( string symbol, int timeframe, int type, int count=WHOLE_ARRAY, int start=0)

 

Описание:

Возвращает индекс найденного наибольшего значения (смещение относительно текущего бара).

 

Параметры:

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

timeframe - Период. Может быть одним из периодов графика. 0 означает период текущего графика.

type - Идентификатор таймсерии. Может быть любым из значений иденитификаторов таймсерий.

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

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

 

 

6 - iLow()

 

Синтаксис:

double iLow( string symbol, int timeframe, int shift)

 

Описание:

Возвращает значение минимальной цены указанного параметром shift бара с соответствующего графика (symbol, timeframe). В случае ошибки функция возвращает 0. Для получения дополнительной информации об ошибке необходимо вызвать функцию GetLastError().

Для текущего графика информация о минимальных ценах находится в предопределенном массиве Low[].

 

Параметры:

symbol - Символьное имя инструмента. NULL означает текущий символ.

timeframe - Период. Может быть одним из периодов графика. 0 означает период текущего графика.

shift - Индекс получаемого значения из таймсерии (сдвиг относительно текущего бара на указанное количество периодов назад).

 

 

7 - iLowest()

 

Синтаксис:

int iLowest( string symbol, int timeframe, int type, int count=WHOLE_ARRAY, int start=0)

 

Описание:

Возвращает индекс найденного наименьшего значения (смещение относительно текущего бара).

 

Параметры:

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

timeframe - Период. Может быть одним из значений периодов графика. 0 означает период текущего графика.

type - Идентификатор таймсерии. Может быть любым из значений идентификаторов таймсерий.

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

start - Смещение (относительно текущего) начального бара, с которого начинается поиск наименьшего значения.

 

 

8 - iOpen()

 

Синтаксис:

double iOpen( string symbol, int timeframe, int shift)

 

Описание:

Возвращает значение цены открытия указанного параметром shift бара с соответствующего графика (symbol, timeframe). В случае ошибки функция возвращает 0. Для получения дополнительной информации об ошибке необходимо вызвать функцию GetLastError().

Для текущего графика информация о ценах открытия находится в предопределенном массиве Open[].

 

Параметры:

symbol - Символьное имя инструмента. NULL означает текущий символ.

timeframe - Период. Может быть одним из периодов графика. 0 означает период текущего графика.

shift - Индекс получаемого значения из таймсерии (сдвиг относительно текущего бара на указанное количество периодов назад).

 

 

9 - iTime()

 

Синтаксис:

datetime iTime( string symbol, int timeframe, int shift)

 

Описание:

Возвращает значение времени открытия указанного параметром shift бара с соответствующего графика (symbol, timeframe). В случае ошибки функция возвращает 0. Для получения дополнительной информации об ошибке необходимо вызвать функцию GetLastError().

Для текущего графика информация о времени открытия каждого бара находится в предопределенном массиве Time[].

 

Параметры:

symbol - Символьное имя инструмента. NULL означает текущий символ.

timeframe - Период. Может быть одним из периодов графика. 0 означает период текущего графика.

shift - Индекс получаемого значения из таймсерии (сдвиг относительно текущего бара на указанное количество периодов назад).

 

 

10 - iVolume()

 

Синтаксис:

double iVolume( string symbol, int timeframe, int shift)

 

Описание:

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

Для текущего графика информация о тиковых объемах каждого бара находится в предопределенном массиве Volume[].

 

Параметры:

symbol - Символьное имя инструмента. NULL означает текущий символ.

timeframe - Период. Может быть одним из периодов графика. 0 означает период текущего графика.

shift - Индекс получаемого значения из таймсерии (сдвиг относительно текущего бара на указанное количество периодов назад).

 

ВНИМАНИЕ! При тестировании ценовые данные того же самого символа, но другого таймфрейма, моделируются точно, за исключением объемов. Объемы других таймфреймов не моделируются. Ценовые данные других символов не моделируются. Во всех случаях количество баров в таймсериях моделируется точно.

 

Надеюсь, данный урок был Вам полезен.

До встречи на следующем уроке!

 

© Kirill. [email protected]

Share this post


Link to post
Share on other sites
Programmer

Урок 47 - Индикатор индикатора Часть 1

 

Всем привет!

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

 

Мы посвятим три урока данной теме. Сегодня мы рассмотрим несколько примеров использования индикатора на индикаторе, во втором уроке данной серии мы узнаем, как именно выполняется данная процедура в терминале MetaTrader 4, а в третьей часте мы изучим, как это делается программно в среде MQL4.

 

Итак, приступим!

 

Пример 1

Пример использования индикатора CCI на графике GBPUSD H1:

 



Рис. 1 - Пример

 

В нижнем окне представлен индикатор CCI с периодом 14 (красный цвет), на который наложен индикатор EMA с периодом 14 (синий цвет). В данном примере мы видим две ситуации, когда можно было бы войти в рынок по сигналу индикатора на индикаторе.

 

  • Ситуация А: CCI пересёк EMA(CCI) сверху вниз - признак того, что высока вероятность продолжения движение CCI вниз - сигнал к продаже. В основном окне красным цветом выделено два бара. Сигнал на продажу оказывается завершённым по завршении первого выделенного бара. Осуществить продажу можно уже на втором баре - как видим, в данной ситуации можно было бы получить хорошую прибыль.
  • Ситуация B: CCI попытался пересечеть EMA(CCI) сверху вниз, но произошёл отскок - признак того, что высока вероятность движения CCI вверх - сигнал к покупке. В основном окне синим цветом выделено два бара. Сигнал на покупку оказывается завершённым по завршении первого выделенного бара. Осуществить покупку можно уже на втором баре - как видим, в данной ситуации можно было бы получить очень хорошую прибыль.

 

 

 

Пример 2

Пример использования индикатора ATR на графике USDJPY H1:

 



Рис. 2 - Пример

 

В нижнем окне представлен индикатор ATR с периодом 14 (голубой цвет), на который наложен индикатор Envelopes с периодом 14 и отклонением 5% (синий и красный цвета). В данном примере мы видим три интересные ситуации.

 

  • Ситуация А: ATR выше верхней линии ENVELOPES(ATR) - т.е. выше 10%-го (2x5%) диапазона отклонения от среднего значения. Это значит, что сейчас волатильность выше, чем она была в среднем за последнее время, и она растёт, значит, инвесторы активны и есть какая-то определённость на рынке - это признак того, что имеющаяся тенденция (рост цены) сохранится некоторое время. Сигнал к покупке.
  • Ситуация B: ATR ниже нижней линии ENVELOPES(ATR) - т.е. ниже 10%-го диапазона отклонения от среднего значения. Это значит, что сейчас волатильность ниже, чем она была в среднем за последнее время, и она падает, значит, активность инвесторов идёт на убыль, т.е. есть какая-то неопределённость на рынке - желательно в это время воздержаться от торговли.
  • Ситуация C: ATR выше верхней линии ENVELOPES(ATR) - т.е. выше 10%-го диапазона отклонения от среднего значения. Это значит, что сейчас волатильность выше, чем она была в среднем за последнее время, и она растёт, значит, инвесторы активны и есть какая-то определённость на рынке - это признак того, что имеющаяся тенденция (падение цены) сохранится некоторое время. Сигнал к продаже.

 

 

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

 

До встречи на следующем уроке!

© Kirill. [email protected]

post-50854-1404215418,0732_thumb.gif

post-50854-1404215418,124_thumb.gif

Share this post


Link to post
Share on other sites
Programmer

Урок 48 - Индикатор индикатора Часть 2

 

Приветствую, уважаемые читатели!

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

Поехали!

 

Как же наложить один индикатор на другой?

Делается это довольно просто, но есть некоторые тонкости.

Во-первых, необходимо нанести первый индикатор на график. Неважно, как Вы это сделаете - можно через меню "Вставка" -> "Индикаторы", а можно через панель "Навигатор".

Теперь, мы будем наносить второй индикатор на первый.

 

  • Тут есть хитрость: если попробовать выполнить данную процедуру через меню "Вставка" -> "Индикаторы" - то ничего не получится. Так устроен терминал MT4. Второй индикатор надо обязательно наносить через панель "Навигатор". Для этого находим интересующий нас индикатор и перетаскиваем его на график.
  • Вторая хитрость: второй индикатор необходимо перетащить именно в то окно, где находится первый индикатор. Если это главное окно - то в главное, если индикатор в отдельном окне - то в это отдельное окно.
  • Теперь в выпадающем списке "Применить к" выбираем либо First Indicator's Data, либо Previous Indicator's Data и жмём ОК.

 

 



Рис. 1 - Процедура

 

Вуаля! Всё готово и должно выглядеть вот так:

 



Рис. 2 - Результат

 

 

В чём же разница между First Indicator's Data и Previous Indicator's Data?

First Indicator's Data - новый индикатор будет наложен на самый первый индикатор данного окна.

Previous Indicator's Data - новый индикатор будет наложен на тот индикатор, который был добавлен к данному окну последним. Используя опцию Previous Indicator's Data, можно получать очень необычные комбинации индикаторов, например:

 



Рис. 3 - Пример

 

 

Замечу, что не все индикаторы можно накладывать на другие индикаторы. Однако, чтобы полноценоо освоить данную технику, надо экспериментировать! Спасибо за внимание. В следующий раз мы рассмотрим код программы, накладывающей индикатор на индикатор.

 

До встречи на следующем уроке!

© Kirill. [email protected]

post-50854-1404215470,7452_thumb.gif

post-50854-1404215470,7965_thumb.gif

post-50854-1404215470,8435_thumb.gif

Share this post


Link to post
Share on other sites
Programmer

Урок 49 - Индикатор индикатора Часть 3

 

Всем привет!

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

Поехали!

 

Код:

//+------------------------------------------------------------------+
//|                                           iMAOnArray_Example.mq4 |
//|                                         Copyright © 2011, Kirill |
//|                                          [email protected] |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2011, Kirill"
#property link      "[email protected]"

#property indicator_separate_window
#property indicator_buffers 2
#property indicator_color1 Red
#property indicator_color2 DarkBlue

double ExtMapBuffer1[];
double ExtMapBuffer2[];

int init()
{
  IndicatorDigits(MarketInfo(Symbol(),MODE_DIGITS));
  SetIndexStyle(0,DRAW_LINE);
  SetIndexBuffer(0,ExtMapBuffer1);
  SetIndexStyle(1,DRAW_LINE,STYLE_SOLID,2);
  SetIndexBuffer(1,ExtMapBuffer2);

  return(0);
}

int deinit()
{
  return(0);
}

int start()
{
  int bar, limit;

  int counted_bars=IndicatorCounted();
  if(counted_bars<0) return(-1);
  if(counted_bars>0) counted_bars--;
  limit=Bars-IndicatorCounted();


  for(bar=0; bar<limit; bar++)
     ExtMapBuffer1[bar] = iCCI(NULL,0,14,PRICE_TYPICAL,bar);

  for(bar=0; bar<limit; bar++)
     ExtMapBuffer2[bar]=iMAOnArray(ExtMapBuffer1,Bars,14,0,MODE_EMA,bar);

  return(0);
}

В данном коде Вам должно быть понятно почти всё. Если у Вас возникают трудности, обратитесь к урокам 10-12 "Ваш первый индикатор". А мы пока продолжим.

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

   for(bar=0; bar<limit; bar++)
     ExtMapBuffer1[bar] = iCCI(NULL,0,14,PRICE_TYPICAL,bar);

  for(bar=0; bar<limit; bar++)
     ExtMapBuffer2[bar]=iMAOnArray(ExtMapBuffer1,Bars,14,0,MODE_EMA,bar);

В первом мы записываем значения индикатора CCI в специально отведённый для этого буфер ExtMapBuffer1. Этот буфер будет отоброжён на экране. Затем мы применяем функцию iMAOnArray() к буферу ExtMapBuffer1 - т.е. мы накладываем индиатор MA на буфер, в котором содержатся значения индикатора CCI. Резальтат записывается в буфер ExtMapBuffer2, который тоже будет отображён на графике. Таким образом, на графике будет отображено два индиатора: CCI (через буфер ExtMapBuffer1) и Moving Average, взятый от CCI, (через буфер ExtMapBuffer2).

 

Вот и всё! Результат выглядит следующим образом:

 



Рис. 1 - Индикатор в работе

 

Замечу, что не все индикаторы можно накладывать на массивы - в MQL4 всего 7 функций, подобных iMAOnArray. Вот они все:

iBandsOnArray()

iCCIOnArray()

iEnvelopesOnArray()

iMomentumOnArray()

iMAOnArray()

iRSIOnArray()

iStdDevOnArray()

 

До встречи на следующем уроке!

© Kirill. [email protected]

post-50854-1404215515,2487_thumb.gif

Share this post


Link to post
Share on other sites
Programmer

Урок 50 - Дата и время

 

Приветствую всех на юбилейном 50-м уроке!

Сегодня мы изучим весьма важный раздел MQL4 - дату и время. Мы уже не раз обращались к функциям, которые рассмотрим сегодня, также мы уже немного изучили дату и время в Уроке 3 - Типы данных в MQL4. Нижеописанные функции помогут Вам ответить на такие вопросы, как: "Наступило ли время для входа советника в рынок?", "Наступило ли время для выхода из рынка?", "Как давно уже существует определённый ордер" - для ответа на последний вопрос необходимо вычесть из текущего времени TimeCurrent() время открытия ордера OrderOpenTime(). Однако, прежде, чем мы подробно рассмотрим функции даты и времени, давайте освежим наши знания и обратимся к типу данных datetime:

 

 

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';

 

 

А теперь рассмотрим функции работы с датой и временем!

 

1 - Day()

 

Синтаксис:

int Day( )

 

Описание:

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

Замечание: при тестировании последнее известное время сервера моделируется.

 

Параметры:

- отсутствуют -

 

 

2 - DayOfWeek()

 

Синтаксис:

int DayOfWeek( )

 

Описание:

Возвращает порядковый номер дня недели (воскресенье-0,1,2,3,4,5,6) последнего известного времени сервера.

Замечание: при тестировании последнее известное время сервера моделируется.

 

Параметры:

- отсутствуют -

 

 

3 - DayOfYear()

 

Синтаксис:

int DayOfYear( )

 

Описание:

Возвращает текущий день года (1-1 января,..,365(6) - 31 декабря), т.е день года последнего известного времени сервера.

Замечание: при тестировании последнее известное время сервера моделируется.

 

Параметры:

- отсутствуют -

 

 

4 - Hour()

 

Синтаксис:

int Hour( )

 

Описание:

Возвращает текущий час (0,1,2,..23) последнего известного серверного времени на момент старта программы (в процессе выполнения программы это значение не меняется).

Замечание: при тестировании последнее известное время сервера моделируется.

 

Параметры:

- отсутствуют -

 

 

5 - Minute()

 

Синтаксис:

int Minute( )

 

Описание:

Возвращает текущую минуту (0,1,2,..59) последнего известного серверного времени на момент старта программы (в процессе выполнения программы это значение не меняется).

Замечание: при тестировании последнее известное время сервера моделируется.

 

Параметры:

- отсутствуют -

 

 

6 - Month()

 

Синтаксис:

int Month( )

 

Описание:

Возвращает номер текущего месяца (1-Январь,2,3,4,5,6,7,8,9,10,11,12), т.е. номер месяца последнего известного времени сервера.

Замечание: при тестировании последнее известное время сервера моделируется.

 

Параметры:

- отсутствуют -

 

 

7 - Seconds()

 

Синтаксис:

int Seconds( )

 

Описание:

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

Замечание: при тестировании последнее известное время сервера моделируется.

 

Параметры:

- отсутствуют -

 

 

8 - TimeCurrent()

 

Синтаксис:

datetime TimeCurrent( )

 

Описание:

Возвращает последнее известное время сервера (время прихода последней котировки) в виде количества секунд, прошедших после 00:00 1 января 1970 года.

 

Замечание: при тестировании последнее известное время сервера моделируется.

 

Параметры:

- отсутствуют -

 

 

9 - TimeDay()

 

Синтаксис:

int TimeDay( datetime date)

 

Описание:

Возвращает день месяца (1 - 31) для указанной даты.

 

Параметры:

date - Дата, представленная в виде количества секунд, прошедших после 00:00 1 января 1970 года.

 

 

10 - TimeDayOfWeek()

 

Синтаксис:

int TimeDayOfWeek( datetime date)

 

Описание:

Возвращает день недели (0-Воскресенье,1,2,3,4,5,6) для указанной даты.

 

Параметры:

date - Дата, представленная в виде количества секунд, прошедших после 00:00 1 января 1970 года.

 

 

11 - TimeDayOfYear()

 

Синтаксис:

int TimeDayOfYear( datetime date)

 

Описание:

Возвращает день (1 - 1 января,..,365(6) - 31 декабря) года для указанной даты.

 

Параметры:

date - Дата, представленная в виде количества секунд, прошедших после 00:00 1 января 1970 года.

 

 

12 - TimeHour()

 

Синтаксис:

int TimeHour( datetime time)

 

Описание:

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

 

Параметры:

time - Дата, представленная в виде количества секунд, прошедших после 00:00 1 января 1970 года.

 

 

13 - TimeLocal()

 

Синтаксис:

datetime TimeLocal( )

 

Описание:

Возвращает локальное компьютерное время в виде количества секунд, прошедших после 00:00 1 января 1970 года.

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

 

Параметры:

- отсутствуют -

 

 

14 - TimeMinute()

 

Синтаксис:

int TimeMinute( datetime time)

 

Описание:

Возвращает минуты для указанного времени.

 

Параметры:

time - Дата, представленная в виде количества секунд, прошедших после 00:00 1 января 1970 года.

 

 

15 - TimeMonth()

 

Синтаксис:

int TimeMonth( datetime time)

 

Описание:

Возвращает номер месяца для указанного времени (1-Январь,2,3,4,5,6,7,8,9,10,11,12).

 

Параметры:

time - Дата, представленная в виде количества секунд, прошедших после 00:00 1 января 1970 года.

 

 

16 - TimeSeconds()

 

Синтаксис:

int TimeSeconds( datetime time)

 

Описание:

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

 

Параметры:

time - Дата, представленная в виде количества секунд, прошедших после 00:00 1 января 1970 года.

 

 

17 - TimeYear()

 

Синтаксис:

int TimeYear( datetime time)

 

Описание:

Возвращает год для указанной даты. Возвращаемая величина может быть в диапазоне 1970-2037.

 

Параметры:

time - Дата, представленная в виде количества секунд, прошедших после 00:00 1 января 1970 года.

 

 

18 - Year()

 

Синтаксис:

int Year( )

 

Описание:

Возвращает текущий год, т.е. год последнего известного времени сервера.

Замечание: при тестировании последнее известное время сервера моделируется.

 

Параметры:

- отсутствуют -

 

Надеюсь, данный урок был Вам полезен.

До встречи на следующем уроке!

 

© Kirill. [email protected]

Share this post


Link to post
Share on other sites
Programmer

Урок 51 - Внешние функции (часть 1)

 

Всем привет!

Давайте посмотрим на "Мастер создания Советника":

 



Рис. 1 - Мастер создания Советника

 

Из предлагаемых им вариантов, мы уже обсудили:

- Советник - Уроки 13-17

- Пользовательский индикатор - Урок 10-12

- Пользовательский скрипт - Урок 18

- Генерация по шаблону - Урок 19

 

Сегодня мы обратимся к опции "Библиотека функций".

Но для начала мы повторим некоторые понятия и концепции из урока 7 "Функции".

 

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

 

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

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

Есть только одно различие между функциями и Вашей мясорубкой: некоторые функции возвращают НИЧЕГО (в 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 ответственно за возвращение итого результата.

 

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

 

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

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

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

 

Допустим, у Вас есть функция, котороая возвращает сумму двух 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 производит присваивание возвращаемого им значения в родготовленную Вами переменную.

 

Это было повторение ключевых моментов урока 7, а сейчас мы перейдём к внешним функциям.

 

Внешние функиции

 

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

Внешние файлы могут быть двух типов:

 

1. Исполняемые MQL4 файлы (*.ex4):

Вы можете использовать функции, которые находятся в откомпилированных MQL4 файлах, называемых библиотеками. Библиотека (библиотечный файл) должен располагаться в папке MetaTrader4\experts\libraries и должны быть скомпилированы (*.ex4).

 

2. DLL-файлы (*.dll)

Про импортирование функций из DLL и даже про создание DLL-файлов мы подробно поговорили в уроках 23-25 "Ваша первая DLL". Добавлю лишь, что помимо создания и использования собственных DLL можно использовать встроенные в систему Windows DLL и прописанные в них функции. Пример будет рассмотрен ниже.

 

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

До встречи на следующем уроке!

 

© Kirill. [email protected]

post-50854-1404215676,4275_thumb.gif

Share this post


Link to post
Share on other sites
Programmer

Урок 52 - Внешние функции (часть 2)

 

Всем привет!

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

 

1 - Импорт функций из библиотек MQL4 (*.ex4)

Для начала создадим библиотечный файл. Для этого вызовите Мастер создания Советника и выберите опцию "Библиотека функций" (см. рис 1).

Затем впишите параметры библиотеки функций и нажмите "Готово":

 



Рис. 1 - Создание библиотеки функций

 

В появившийся файл вбейте следующий код и откомпилируйте его:

//+------------------------------------------------------------------+
//|                                               MyFirstLibrary.mq4 |
//|                                Copyright © 2011, StockProgrammer |
//|                                          [email protected] |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2011, StockProgrammer"
#property link      "[email protected]"

//+------------------------------------------------------------------+
//| My function                                                      |
//+------------------------------------------------------------------+
int MyCalculator(int value, int value2)
{
  return(value+value2);
}
//+------------------------------------------------------------------+

 

Данная библиотека содержит только одну функцию - MyCalculator(), которая складывает две переменные типа Integer и возвращает результат.

После компиляции библиотеки в папке MetaTrader4\experts\libraries появятся два файла: "MyFirstLibrary.mq4" и "MyFirstLibrary.ex4". Последний для нас наиболее важен.

 

Теперь создадим простую программу (скипт, например), которая импортирует откомпилированную библиотеку и применяет прописанную в ней функцию:

 

//+------------------------------------------------------------------+
//|                                         External functions 1.mq4 |
//|                                Copyright © 2011, StockProgrammer |
//|                                          [email protected] |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2011, StockProgrammer"
#property link      "[email protected]"

#import "MyFirstLibrary.ex4"
 int MyCalculator(int value, int value2);
#import

//+------------------------------------------------------------------+
//| script program start function |
//+------------------------------------------------------------------+
int start()
{
  int result = MyCalculator(10, 20);
  Alert(result);

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

 

В данном коде мы совершили два шага:

1 - импортировали бибилиотеку

2 - вызвали функцию из библиотеки

 

#import "MyFirstLibrary.ex4"
 int MyCalculator(int value, int value2);
#import

 

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

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

 

#import "MyFirstLibrary.ex4"
 int MyCalculator1(int value, int value2);
#import "MyFirstLibrary.ex4"
 double MyExtFunction2(double value3);
#import 

 

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

 

2 - Импорт функций из DLL-файлов (*.dll)

 

//+------------------------------------------------------------------+
//|                                         External functions 2.mq4 |
//|                                Copyright © 2011, StockProgrammer |
//|                                          [email protected] |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2011, StockProgrammer"
#property link      "[email protected]"

#import "user32.dll"
 int MessageBoxA(int hWnd,string lpText,string lpCaption,int uType); 

//+------------------------------------------------------------------+
//| script program start function |
//+------------------------------------------------------------------+


int start()
{
  int result = MessageBoxA(NULL,"Hello from StockProgrammer!","MQL4 MessageBox",0);
  return(0);
}
//+------------------------------------------------------------------+

 

Всё точно также делается. Единственное отличие - не надо закрывать вызов файла строчкой "#import". Например, приведённый код позволяет вызвать встроенную в Windows функцию "MessageBoxA()". В результате появляется новое окно с Вашим сообщением:

 



Рис. 2 - Оконо с сообщением

 

Надеюсь, данный урок Вам был полезен!

До встречи на следующем уроке!

 

© Kirill. [email protected]

post-50854-1404215694,5036_thumb.gif

post-50854-1404215694,5458_thumb.gif

Share this post


Link to post
Share on other sites
Programmer

Урок 53 - Информация о счете

 

Приветствую, уважаемые читатели меого курса по программированию!

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

 

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

 

1 - AccountBalance( )

 

Синтаксис:

double AccountBalance( )

 

Описание:

Возвращает значение баланса активного счета (сумма денежных средств на счете).

 

Параметры:

- отсутствуют -

 

 

2 - AccountCredit( )

 

Синтаксис:

double AccountCredit( )

 

Описание:

Возвращает значение кредита для активного счета.

 

Параметры:

- отсутствуют -

 

 

3 - AccountCompany( )

 

Синтаксис:

string AccountCompany( )

 

Описание:

Возвращает название брокерской компании, в которой зарегистрирован текущий счет.

 

Параметры:

- отсутствуют -

 

 

4 - AccountCurrency( )

 

Синтаксис:

string AccountCurrency( )

 

Описание:

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

 

Параметры:

- отсутствуют -

 

 

5 - AccountEquity( )

 

Синтаксис:

double AccountEquity( )

 

Описание:

Возвращает сумму собственных средств для текущего счета. Расчет equity зависит от настроек торгового сервера.

 

Параметры:

- отсутствуют -

 

 

6 - AccountFreeMargin( )

 

Синтаксис:

double AccountFreeMargin( )

 

Описание:

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

 

Параметры:

- отсутствуют -

 

 

7 - AccountFreeMarginCheck( string symbol, int cmd, double volume)

 

Синтаксис:

double AccountFreeMarginCheck( string symbol, int cmd, double volume)

 

Описание:

Возвращает размер свободных средств, которые останутся после открытия указанной позиции по текущей цене на текущем счете. Если свободных средств не хватает, то будет сгенерирована ошибка 134 (ERR_NOT_ENOUGH_MONEY).

 

Параметры:

symbol - Наименование финансового инструмента, с которым должна проводиться торговая операция.

cmd - Торговая операция. Может быть либо OP_BUY, либо OP_SELL.

volume - Количество лотов.

 

 

8 - AccountFreeMarginMode( )

 

Синтаксис:

double AccountFreeMarginMode( )

 

Описание:

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

 

0 - при расчете не используются нереализованные прибыли и убытки;

1 - при расчете свободных средств используется как нереализованная прибыль, так и убыток по открытым позициям на текущем счете;

2 - при расчете используется только значение прибыли, текущий убыток по открытым позициям не учитывается;

3 - при расчете используется только значение убытка, текущая прибыль по открытым позициям не учитывается.

 

Параметры:

- отсутствуют -

 

 

9 - AccountLeverage( )

 

Синтаксис:

int AccountLeverage( )

 

Описание:

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

 

Параметры:

- отсутствуют -

 

 

10 - AccountMargin( )

 

Синтаксис:

double AccountMargin( )

 

Описание:

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

 

Параметры:

- отсутствуют -

 

 

11 - AccountName( )

 

Синтаксис:

string AccountName( )

 

Описание:

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

 

Параметры:

- отсутствуют -

 

 

12 - AccountNumber( )

 

Синтаксис:

int AccountNumber( )

 

Описание:

Возвращает номер текущего счета.

 

Параметры:

- отсутствуют -

 

 

13 - AccountProfit( )

 

Синтаксис:

double AccountProfit( )

 

Описание:

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

 

Параметры:

- отсутствуют -

 

 

14 - AccountServer( )

 

Синтаксис:

string AccountServer( )

 

Описание:

Возвращает имя активного сервера.

 

Параметры:

- отсутствуют -

 

 

15 - AccountStopoutLevel( )

 

Синтаксис:

int AccountStopoutLevel( )

 

Описание:

Возвращает значение уровня, по которому определяется состояние Stop Out.

 

Параметры:

- отсутствуют -

 

 

16 - AccountStopoutMode( )

 

Синтаксис:

int AccountStopoutMode( )

 

Описание:

Возвращает режим расчета уровня Stop Out. Режим расчета может принимать следующие значения:

 

0 - расчет процентного соотношения залоговой маржи к средствам;

1 - сравнение уровня свободной маржи с абсолютным значением.

 

Параметры:

- отсутствуют -

 

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

Подробнее - см. Урок 35 "Защита MQL4-программ (часть 2)".

 

Надеюсь, данный урок был Вам полезен.

До встречи на следующем уроке!

 

© Kirill. [email protected]

Share this post


Link to post
Share on other sites
Programmer

Урок 54 - Флаги (часть 1)

 

Всем привет.

Недавно получил сообщение от одного из читателей моего курса по программированию:

 

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

 

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

Всё дело в флагах!

 



Рис. 1 - Сигнальные флаги

 

Что такое флаги и зачем они нужны?

Флаг в программировании- это общее название переменной, характеризующей какое-либо состояние программы в каждый момент её исполнения. В общем случае, флаг может принимать самые разные значения, но в большинстве члучаев в качестве флагов используются булевы переменные, принимающие только два значения: TRUE и FALSE. Таким образом, флаг - это своебразный переключатель. TRUE - означает, что какое-то свойство программы находится в режиме А, FALSE - означает, что это свойство в режиме B.

 

Давайте разберём на примере, чтобы принцип работы флагов стал понятнее. В вопросе, который отображён в начале данного урока, читатель предлагает проверять условие на открытие только в случае, если по данной валютной паре на текущем таймбаре (это подразумевается) не было закрыто ни одного ордера. Если был закрыт хоть один - то ничего не делаем, ждём следующего таймбара. Для решения поставленной задачи мы могли бы на каждом тике переберать все закрытые ордера и узнавать - был ли такой, который закрылся на данном баре. И каждый раз принимать решение о том, переходить к торговле или нет. Но это было бы нецелесообразно! Действительно, пусть, например, мы работаем на таймфрейме D1, и в начале дня, на одном из тиков мы уже выяснили, что появился закрытый в текущем баре ордер. Теперь, мы знаем, что торговать на этом тике нельзя. Но также мы можем сделать логический вывод, что согласно описанному алгоритму торговать на всех последующих тиках текущего дня тоже нельзя. И что теперь? Мы будем каждый раз проверять заведомо верное утверждение? Нет! Мы воспользуемся нашим знанием того, что торговля запрещена до конца текущего таймбара (дня на D1). А чтобы это сделать, мы создадим переменную-флаг was_closed, которая будет принимать значение "TRUE", если на текущем таймбаре был найден закрытый ордер, и значение "FALSE", если такой бар найден не был. Таким образом, мы сможем хранить состояние программы для последующего использования.

 

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

 

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

 

До встречи на следующем уроке!

 

© Kirill. [email protected]

post-50854-1404215723,2169_thumb.gif

Share this post


Link to post
Share on other sites
Programmer

Урок 55 - Флаги (часть 2)

 

Всем привет.

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

 

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


Рис. 1 - Алгоритм

 

Пояснения

Выглядит страшно? На самом деле всё легко. Я подготовил пояснения, чтобы помочь Вам разобраться:

1. Проверяем появился новый бар или нет. Да - тогда обнуляем наш флаг.

2. Проверяем в каком режиме флаг. Если TRUE - значит хоть один ордер был закрыт на текущем баре, торговать нельзя, завершаем функцию start, новый тик перенесёт нас в самое начало. Если FALSE - значит пока, закрытый на текущем баре, не обнаружен.

3. Начинаем цикл по всем закрытым оредрам.

4. Выбираем конкретный ордер - проверяем он был закрыт на текущем баре или нет. Если TRUE - переводим флаг в режим TRUE и выходим из цикла. Если FALSE - уменьшаем переменную i (decr(i) - в целях экономии времени мы идём от самого свежего закрытого ордера к самому старому) и переходим к следующему шагу цикла.

5. Цикл завершён, либо преждевременно прекращён - проверяем в каком режиме флаг. Если TRUE - значит в цикле был обнаружен ордер, который был закрыт на текущем баре, - торговать нельзя, завершаем функцию start, новый тик перенесёт нас в самое начало. Если FALSE - значит такого ордера обнаружено не было - выполняем торговую стратегию.

 

До встречи на следующем уроке!

 

© Kirill. [email protected]

post-50854-1404215747,6138_thumb.gif

Share this post


Link to post
Share on other sites
Programmer

Урок 56 - Флаги (часть 3)

 

Всем привет.

Сегодня мы продолжаем изучать флаги. Алгоритм мы уже рассмотрели. Остался только код!

 

Сразу в бой!

 

//+------------------------------------------------------------------+
//|                                                        Flags.mq4 |
//|                                Copyright © 2011, StockProgrammer |
//|                                          [email protected] |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2011, StockProgrammer"
#property link      "[email protected]"

//+------------------------------------------------------------------+
//| script program start function |
//+------------------------------------------------------------------+
int start()
{
  static bool was_closed = false;        //флаг, показывающий был ли закрыт ордер на данном баре
  if(IsNewBar()==true)                   //начался новый бар - обнуляем флаг
     was_closed = false;
  if(was_closed == false)                //флаг говорит нам, что ордер не был закрыт 
  {
     for(int i=OrdersHistoryTotal()-1; i>=0; i--)
     {                                   //перебираем ордера в истории, начиная с самого свежего
        OrderSelect(i, SELECT_BY_POS, MODE_HISTORY);
        if(OrderCloseTime()>=Time[0])    //нашли ордер, который был закрыт на текущем баре
        {
           was_closed = true;            //ставим флаг в режим: ордер был закрыт на текущем баре
           break;                        //выходим из цикла
        }
     }
     if(was_closed == false)             //проверяем, что флаг не был изменён в цикле
     {
        //...                            //проверяем условие на вход
     }
                                         //иначе: ждём нового бара
  }
  return(0);
}

//функция, которая проверяет наступил новый бар или нет
bool IsNewBar()
{
  static datetime BARflag = 0;
  datetime now = Time[0];
  if(BARflag < now)
  {
     BARflag = now;         
     return(1);
  }

  else
  {
     return(0);
  }
}

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

 

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

 

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

До встречи на следующем уроке!

 

© Kirill. [email protected]

Share this post


Link to post
Share on other sites
Programmer

Урок 57 - Проверка состояния (Часть 1)

 

Всем привет! Иногда возникают ситуации при работе советника, когда необходимо узнать состояние окружающей среды, в которой исполняется код советника в данном, конкретном случае. Хоть эта информация и не является частью рабочего алгоритма советника (алгоритма принятия решений), окружающая среда и условия, в которых запущен советник, могут значительно влиять на его работу. Например, если советнику запрещено подгружать DLL (которые мы уже научились создавать и прикреплять :) ), а он их собирается использовать, то работа советника будет некорректной - он либо не сможет торговать, либо, что хуже, - будет торговать неверно.

 

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

 

PS: не пугайтесь термина "окружающая среда" - это термин программирования, относящийся к условиям, в которых программа исполняется, термин не имеет никакого отношения к Природе :D

 

1 - GetLastError()

 

Синтаксис:

int GetLastError( )

 

Описание:

Функция возвращает код последней ошибки, после чего значение специальной переменной last_error, в которой хранится код последней ошибки обнуляется. Так что последующий вызов GetLastError() вернет значение 0.

 

Параметры:

- отсутствуют -

 

 

2 - IsConnected()

 

Синтаксис:

bool IsConnected( )

 

Описание:

Возвращает состояние главного соединения клиентского терминала с сервером, по которому производится подкачка данных. TRUE - связь с сервером установлена, FALSE - связь с сервером отсутствует или прервана.

 

Параметры:

- отсутствуют -

 

 

3 - IsDemo()

 

Синтаксис:

bool IsDemo( )

 

Описание:

Возвращается TRUE, если программа работает на демонстрационном счете, в противном случае возвращает FALSE.

 

Параметры:

- отсутствуют -

 

 

4 - IsDllsAllowed()

 

Синтаксис:

bool IsDllsAllowed( )

 

Описание:

Возвращает TRUE, если DLL вызов функции разрешены для эксперта, иначе возвращает FALSE.

 

Параметры:

- отсутствуют -

 

 

5 - IsExpertEnabled()

 

Синтаксис:

bool IsExpertEnabled( )

 

Описание:

Возвращает TRUE, если в клиентском терминале разрешен запуск экспертов, иначе возвращает FALSE.

 

Параметры:

- отсутствуют -

 

 

6 - IsLibrariesAllowed()

 

Синтаксис:

bool IsLibrariesAllowed( )

 

Описание:

Возвращает TRUE, если эксперт может назвать библиотечную функцию, иначе возвращает FALSE.

 

Параметры:

- отсутствуют -

 

 

7 - IsOptimization()

 

Синтаксис:

bool IsOptimization( )

 

Описание:

Возвращается TRUE, если эксперт работает в режиме оптимизации тестирования, иначе возвращает FALSE.

 

Параметры:

- отсутствуют -

 

 

8 - ()

 

Синтаксис:

bool IsStopped( )

 

Описание:

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

 

Параметры:

- отсутствуют -

 

 

9 - IsTesting()

 

Синтаксис:

bool IsTesting( )

 

Описание:

Возвращается TRUE, если эксперт работает в режиме тестирования, иначе возвращает FALSE.

 

Параметры:

- отсутствуют -

 

 

10 - IsTradeAllowed()

 

Синтаксис:

bool IsTradeAllowed( )

 

Описание:

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

 

Параметры:

- отсутствуют -

 

 

11 - IsTradeContextBusy()

 

Синтаксис:

bool IsTradeContextBusy( )

 

Описание:

Возвращается TRUE, если поток для выполнения торговых операций занят, иначе возвращает FALSE.

 

Параметры:

- отсутствуют -

 

 

12 - IsVisualMode()

 

Синтаксис:

bool IsVisualMode( )

 

Описание:

Возвращается TRUE, если эксперт тестируется в режиме визуализации, иначе возвращает FALSE.

 

Параметры:

- отсутствуют -

 

 

13 - UninitializeReason()

 

Синтаксис:

int UninitializeReason( )

 

Описание:

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

 

Параметры:

- отсутствуют -

 

 

До встречи на следующем уроке!

 

© Kirill. [email protected]

Share this post


Link to post
Share on other sites
Programmer

Урок 58 - Проверка состояния (Часть 2)

 

Приветствую, уважаемые читатели!

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

 

 

Пример 1 - IsExpertEnabled()

 

int start()
{
  if(IsExpertEnabled()==true)   //советникам разрешено торговать
  {
     //рабочий алгоритм советника
  }
  else  //советникам не разрешено торговать
  {
       Alert("Attention! Please press the \"Expert Advisors\" button in MT4");
  }
  return(0);
}

 

В данном случае при каждом запуске функции start() мы проверяем, что кнопка "Советники" в МТ4 включена, т.е. советникам разрешено торговать. Если это условие выполнено, советник переходит к торговому алгоритму. Если это условие не выполнено - советник выдает сообщение об ошибке, а торговый алгоритм не выполняется.

 

Заметьте, как здесь я использовал корректное ветвление - существует только одна точка выхода из функции start(). Некоторые авторы/программисты предлагают в данной ситуации следующий код:

 

int start()
{
  if(IsExpertEnabled()==false)   //советникам не разрешено торговать
  {
   Alert("Attention! Please press the \"Expert Advisors\" button in MT4");
   return(1);
  }

  //рабочий алгоритм советника

  return(0);
}

 

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

 

 

Пример 2 - UninitializeReason()

 

int deinit()
{
 switch(UninitializeReason())
 {
    case REASON_CHARTCLOSE:
    case REASON_REMOVE:      CleanUp(); break;    // очистка и освобождение ресурсов.
    case REASON_RECOMPILE:
    case REASON_CHARTCHANGE:
    case REASON_PARAMETERS:
    case REASON_ACCOUNT:     StoreData(); break;  // подготовка к рестарту.
 }
 //...
}

 

Данный пример иллюстрирует то, что даже при завершении работы советника вы можете можете выполнять различный завершающий код в зависимости от причины деинитализации. Например, в случае, если программа была удалена с графика (REASON_REMOVE), может быть необходимость отчистить график от лишних объектов, а если был сменен счет (REASON_ACCOUNT) - сохранить данные программы, относящиеся к предыдущему счету. Кстати, если вы забыли как работает оператор switch - повторите Урок 6 - Циклы и Условия (часть 2). Хотя уже надо знать наизусть ;)

 

 

Пример 3 - GetLastError()

 

int ticket;
ticket = OrderSend(Symbol(), OP_BUY, 0.1, Ask, 3, Bid-StopLoss*Point, Bid+TakeProfit*Point);
if(ticket<0)
{
 Print("OrderSend failed with error #",GetLastError());
 return(0);
}

 

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

 

Надеюсь, Вам пригодятся функции проверки в вашей работе.

До встречи на следующем уроке!

 

© Kirill. [email protected]

Share this post


Link to post
Share on other sites
Programmer

Урок 59 - Математические функции

 

Приветствую всех читателей моего курса по программированию! В среде MQL4 можно решать разного рода задачи - в том числе и математические. Сразу предупреждаю, что очень сложные вычисления сделать не получится - этот язык программирования предназначен для написания торговых роботов, а не реализации комплексных математических алгоритмов. Однако, если в анализ интегрирован непростой математический алгоритм, и громоздкие вычисления всё же требуется, то и тут есть решение - данный алгоритм можно реализовать в специализированной среде (например MATHCAD), а затем прицепить его к MQL4 с помощью DLL, но это уже тема совершенно другого урока. Сегодня мы рассмотрим доступные в MQL4 математические функции.

 

1 - MathAbs()

 

Синтаксис:

double MathAbs( double value)

 

Описание:

Функция возвращает абсолютное значение (значение по модулю) переданного ей числа

 

Параметры:

value - Числовая величина.

 

 

2 - MathArccos()

 

Синтаксис:

double MathArccos( double x)

 

Описание:

Функция возвращает значение арккосинуса x в диапазоне 0 к pi в радианах. Если x меньше -1 или больше 1, функция возвращает NaN (неопределенное значение).

 

Параметры:

x - Значение между -1 и 1, арккосинус которого должен быть вычислен.

 

 

3 - MathArcsin()

 

Синтаксис:

double MathArcsin( double x)

 

Описание:

Функция возвращает арксинус x в диапазоне от -pi/2 до pi/2 радианов. Если x-, меньше -1 или больше 1, функция возвращает NaN (неопределенное значение).

 

Параметры:

x - Значение, для которого должен быть вычислен арксинус.

 

 

4 - MathArctan()

 

Синтаксис:

double MathArctan( double x)

 

Описание:

Функция возвращает арктангенс x. Если x равен 0, функция возвращает 0. MathArctan возвращает значение в диапазоне от -pi/2 до pi/2 радианов.

 

Параметры:

x - Число, представляющее тангенс.

 

 

5 - MathCeil()

 

Синтаксис:

double MathCeil( double x)

 

Описание:

Функция возвращает числовое значение, представляющую наименьшее целое число, которое больше или равно x.

 

Параметры:

x - Числовая величина.

 

 

6 - MathCos()

 

Синтаксис:

double MathCos( double value)

 

Описание:

Функция возвращает косинус угла.

 

Параметры:

value - Угол в радианах.

 

 

7 - MathExp()

 

Синтаксис:

double MathExp( double d)

 

Описание:

Функция возвращает значение числа e в степени d. При переполнении функция возвращает INF (бесконечность), в случае потери порядка MathExp возвращает 0.

 

Параметры:

d - Число, определяющее степень.

 

 

8 - MathFloor()

 

Синтаксис:

double MathFloor( double x)

 

Описание:

Функция возвращает числовое значение, представляющее наибольшее целое число, которое меньше или равно x.

 

Параметры:

x - Числовое значение.

 

 

9 - MathLog()

 

Синтаксис:

double MathLog( double x)

 

Описание:

Функции возвращают натуральный логарифм x в случае успеха. Если x отрицателен, функция возвращает NaN (неопределенное значение). Если x равен 0, функция возвращает INF (бесконечность) .

 

Параметры:

x - Значение, логарифм которого должен быть вычислен.

 

 

10 - MathMax()

 

Синтаксис:

double MathMax( double value1, double value2)

 

Описание:

Функция возвращает максимальное из двух числовых значений.

 

Параметры:

value1 - Первое числовое значение.

value2 - Второе числовое значение.

 

 

11 - MathMin()

 

Синтаксис:

double MathMin( double value1, double value2)

 

Описание:

Функция возвращает минимальное из двух числовых значений.

 

Параметры:

value1 - Первое числовое значение.

value2 - Второе числовое значение.

 

 

12 - MathMod()

 

Синтаксис:

double MathMod( double value, double value2)

 

Описание:

Функция возвращает вещественный остаток от деления двух чисел.

 

Функция MathMod рассчитывает вещественный остаток f от x / y таким образом, что x = i * y + f , где i является целым числом, f имеет тот же знак, что и x, и абсолютное значение f меньше, чем абсолютное значение y.

 

Параметры:

value - Значение делимого.

value2 - Значение делителя.

 

 

13 - MathPow()

 

Синтаксис:

double MathPow( double base, double exponent)

 

Описание:

Функция возвращает значение основания, возведенного в указанную степень.

 

Параметры:

base - Основание.

exponent - Значение степени.

 

 

14 - MathRand()

 

Синтаксис:

int MathRand( )

 

Описание:

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

 

Параметры:

- отсутствуют -

 

 

15 - MathRound()

 

Синтаксис:

double MathRound( double value)

 

Описание:

Функция возвращает значение, округленное до ближайшего целого числа указанного числового значения.

 

Параметры:

value - Числовая величина для округления.

 

 

16 - MathSin()

 

Синтаксис:

double MathSin( double value)

 

Описание:

Функция возвращает синус указанного угла.

 

Параметры:

value - Угол в радианах.

 

 

17 - MathSqrt()

 

Синтаксис:

double MathSqrt( double x)

 

Описание:

Функция возвращает квадратный корень x. Если x отрицателен, MathSqrt возвращает NaN (неопределенное значение).

 

Параметры:

x - Положительная числовая величина.

 

 

18 - MathSrand()

 

Синтаксис:

void MathSrand( int seed)

 

Описание:

Функция устанавливает начальное состояние для генерации ряда псевдослучайных целых чисел. Чтобы переинициализировать генератор (т.е. установить генератор в предыдущее начальное состояние), необходимо использовать значение 1 в качестве инициализирующего параметра. Любое другое значение для начального числа устанавливает генератор в случайную отправную точку. MathRand возвращает подряд сгенерированные псевдослучайные числа. Вызов MathRand перед любым вызовом MathSrand генерирует ту же самую последовательность, что и запрос MathSrand с параметром 1.

 

Параметры:

seed - Начальное число для ряда случайных чисел.

 

 

19 - MathTan()

 

Синтаксис:

double MathTan( double x)

 

Описание:

Функция возвращает тангенс x. Если x больше или равен 263 или меньше или равен -263, то происходит потеря значения и функция возвращает неопределенное число.

 

Параметры:

x - Угол в радианах.

 

 

До встречи на следующем уроке!

 

© Kirill. [email protected]

Share this post


Link to post
Share on other sites
Programmer

Урок 60 - Применение функций MathSrand() и MathRand() (Часть 1)

 

Всем привет!

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

 

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

 

Итак, торговая система на случайных числах:

 

1. Пара GBPJPY

2. Торгуем например с 7-00 до 15-00

3. Торгуем двумя ордерами: 1-й ордер открывается со sl - 70 tp - 140, 2-й ордер sl - 70, без tp, закрываем в 15-00

4. Генерируем случайное число: если "1" то открывается ордер "buy", если "0" - то "sell"

 

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

 

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

int            Magic = 1010;
extern int MM         = 0; // 0- без МаниМенеджмента , 
                          // 1- ставит лот в минимальный лот после убытка
                          // 2- увеличивает лот до максимума после 3 последовательных убытков
                          // 3- лот зависит только от свободных средств и риска Risk
extern double Lots    = 0.1;
extern double Risk    = 0.05;
extern int     sl1    = 70;
extern int     tp1    = 140;
extern int     sl2    = 70;
extern int     tp2    = 140;

extern int     Time1 = 7;
extern int     Time2 = 15;
extern int     X     = 0;
extern int     EMPTYVAR = 0;
      bool    today = false;
      int     slip  = 3;     
int srand;
int init()
{
  ReadSRand();   
  return(0);
}

int deinit()
{
  SaveSRand();
  return(0);
}

int start()
{
     int J, i;
     double lots;
     srand++;
     if(Hour() > Time1 && Hour() < Time2 && (!today))
     {
        lots= LotsOptimized(); 
        MathSrand(srand);
        //MathSrand(Bid*MathPow(10,Digits));
        J = MathRand();
        J = J % 2;
        Alert("J = ", J);
        if(J==X)
        {
           OrderSend(Symbol(), OP_BUY, lots, ND(Ask), slip, ND(Ask - sl1*Point), ND(Ask + tp1*Point), "BUY1", Magic);
           OrderSend(Symbol(), OP_BUY, lots, ND(Ask), slip, ND(Ask - sl1*Point), ND(0)             , "BUY2", Magic);
        }
        else
        {
           OrderSend(Symbol(), OP_SELL, lots, ND(Bid), slip, ND(Bid + sl2*Point), ND(Bid - tp2*Point), "Sell1", Magic);
           OrderSend(Symbol(), OP_SELL, lots, ND(Bid), slip, ND(Bid + sl2*Point), ND(0)             , "Sell2", Magic);
        }

        today = true;
     }


     else if(Hour() == Time2 && today)
        for(i=0; i<OrdersTotal(); i++)
        {
           OrderSelect(i, SELECT_BY_POS);
           if(OrderType() == OP_BUY)
              OrderClose(OrderTicket(), OrderLots(), ND(Bid), slip);
           else if(OrderType() == OP_SELL)
              OrderClose(OrderTicket(), OrderLots(), ND(Ask), slip);
        }

     if(Hour() >= Time2)
        today = false;

  return(0);
}

//+------------------------------------------------------------------+
double LotsOptimized()
{
  double lot=Lots;
  double lastprofit=0,lp1=0,lp2=0;

  for(int i=0;i<OrdersHistoryTotal() ;i++)
  {
     if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==false)  break;
     lp2=lp1;
     lp1=lastprofit;
     lastprofit=OrderProfit();
  }

  lot=NormalizeDouble(AccountFreeMargin()*Risk/1000.0,1);
  if (MM==0 ) return(Lots);
  if (MM==1 && lastprofit<0)  return(Lots);
  if (MM==2 )
  {
     if (lastprofit<0 && lp1<0 && lp2<0 ) return(lot);
     else return(Lots);
  }

  if(lot<Lots) lot=Lots;
  if (lot>10) lot=10;
  return(lot);
}
//+------------------------------------------------------------------+

void SaveSRand()
{
   int handle = FileOpen("srand.txt",FILE_READ|FILE_WRITE|FILE_CSV,";");
   if(handle==-1)Print("Error file");
   FileSeek(handle,0,SEEK_SET);
   if(handle!=-1)
   {
     FileWrite(handle,srand);
     FileFlush(handle);
     FileClose(handle);
  }
}
void ReadSRand()
{
  int FileHandle=FileOpen("srand.txt",FILE_READ);
  if(FileHandle!=-1)
  {
     FileSeek(FileHandle,0,SEEK_SET);
     srand=StrToInteger(FileReadString(FileHandle));
  }
}

//------------------------------------------ND------------------------------------------

double ND(double val)
{
  return(NormalizeDouble(val, Digits));
}

 

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

Внимание: на реальном счету категорически не советуется запускать данного эксперта.

 

До встречи на следующем уроке!

 

© Kirill. [email protected]

Share this post


Link to post
Share on other sites
Programmer

Урок 61 - Применение функций MathSrand() и MathRand() (Часть 2)

 

Приветствую, уважаемые читатели!

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

 

Итак, начнем!

 

Код:

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

int            Magic = 1010;
extern int MM         = 0; // 0- без МаниМенеджмента , 
                          // 1- ставит лот в минимальный лот после убытка
                          // 2- увеличивает лот до максимума после 3 последовательных убытков
                          // 3- лот зависит только от свободных средств и риска Risk
extern double Lots    = 0.1;
extern double Risk    = 0.05;
extern int     sl1    = 70;
extern int     tp1    = 140;
extern int     sl2    = 70;
extern int     tp2    = 140;

extern int     Time1 = 7;
extern int     Time2 = 15;
extern int     X     = 0;
extern int     EMPTYVAR = 0;
      bool    today = false;
      int     slip  = 3;     
int srand;

Разбор:

Заголовок и внешние переменные. Из внешних переменных нас интересуют следующие:

Time1 - время начала торгов

Time2 - время окончания торгов

X - критерий, либо "0", либо "1" (см. ниже)

EMPTYVAR - данная переменная в алгоритме советника не исспользуется. Она нужна лишь для оптимизации. Например, задав начальное значение оптимизации этой переменной "1", конечное - "100", шаг - "1", можно понаблюдать за прогоном советника 100 раз с одними и теми же параметрами и увидеть, что каждый раз получается новый результат! Вот, что получилось у меня:

 



Рис. 1 - Прогоны с одними и теме же параметрами

 

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

today - переменная-флаг, делающая так, чтобы советник не открывал кучу ордеров, на каждом тике. Подробнее про флаги - см. уроки 54-56 "Флаги".

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

 

Код:

int init()
{
  ReadSRand();   
  return(0);
}

int deinit()
{
  SaveSRand();
  return(0);
}

Разбор:

Для того, чтобы генератор случайных чисел выдал некое псевдослучайное число, его [генератор] надо установить в отправную точку. Каждая отправная точка будет выдавать свое случайное число, и если задать одну и ту же отправную точку дважды, то получатся одинаковые случайные числа (поэтому они и называются псевдослучайными). Обычно в качестве отправной точки используют текущее время. При работе в реальном режиме время постоянно растет (в формате datetime), поэтому и случайные числа будут получаться разные. Однако, при прогоне на истории время моделируется - при двух различных прогонах время будет одинаково меняться. Следовательно, при прогоне советника на истории будут выдаваться одни и те же псевдослучайные числа. Чтобы избежать подобной ситуации, здесь используется хитрый алгоритм, который сохраняет в файл значение отправной точки при завершении работы советника, а при повторном запуске (на реале или на истории) считывает это значение и увеличивает его. Таким образом, значение отправной точки все время меняется, потому и последовательности псевдослучайных чисел всегда будут разные!

 

Код:

     srand++;
     //...
        MathSrand(srand);
        J = MathRand();
        J = J % 2;
        Alert("J = ", J);

Разбор:

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

Важно понимать, что нет значения чему оно равно - главное, чтобы оно было отлично от использованных ранее!

Устанавливаем значение отправной точки генератора случайных чисел.

Записываем в переменную "J" псевдослучайное целое число в дипазоне от 0 до 32767.

Находим остаток от деления "J" на 2 - это либо 1, либо 0. Записываем новое значение в переменную "J" поверх старого.

Выводим на экран.

 

Код:

        if(J==X)
        {
           //BUY
        }
        else
        {
           //SELL
        }

Разбор:

Если J==X (по умолчанию 0), то покупаем. Иначе - продаем.

PS: Про Money Management поговорим в одном из будущих уроках. Сейчас сосредоточимся на генераторе случайных чисел.

 

Код:

void SaveSRand()
{
   int handle = FileOpen("srand.txt",FILE_READ|FILE_WRITE|FILE_CSV,";");
   if(handle==-1)Print("Error file");
   FileSeek(handle,0,SEEK_SET);
   if(handle!=-1)
   {
     FileWrite(handle,srand);
     FileFlush(handle);
     FileClose(handle);
  }
}

Разбор:

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

 

Код:

void ReadSRand()
{
  int FileHandle=FileOpen("srand.txt",FILE_READ);
  if(FileHandle!=-1)
  {
     FileSeek(FileHandle,0,SEEK_SET);
     srand=StrToInteger(FileReadString(FileHandle));
  }
}

Разбор:

Считывает значение последней отправной точки из файла.

 

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

До встречи на следующем уроке!

 

© Kirill. [email protected]

post-50854-1404215990,1524_thumb.gif

Edited by Programmer

Share this post


Link to post
Share on other sites
Programmer

Урок 62 - Псевдослучайные числа

 

Приветствую всех!

Сегодняшний урок необязательный - но при этом он полезен в плане общего развития.

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

 

Итак, Начнем!

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

 

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

 

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

 



Рис. 1 - Эпикур

 

Лучше всего, если сегодня Вы будете воспринимать понятие "случайность" на интуитивном уровне - примерно так: "случайность" - это событие, которое возникает само по себе и никак от нас не зависящее. Отсюда будет следовать, что случайное число - это число, которое появилось (на экране / в памяти компьютера / в воображении человека) абсолютно случайно, т.е. не было никак нами спровоцировано. Теперь становится понятно, почему в информатики считается, что случайных чисел быть не может! Поясню: допустим, в памяти компьютера оказалось случайное число. Зададим вопрос: как оно там окозалось? - Мы его туда записали. Как мы его получили? - Какой-то хитрой функцией. Так вот: какой бы хитрой эта функция ни была (например, она может выдавать в качестве случайного число равное температуре процессора разделить на 15) - число, которое мы будем получать не будем случайным. Просто потому что мы как-то повлияли на его появление!

 

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

 

"Генератор псевдослучайных чисел (ГПСЧ, англ. Pseudorandom number generator, PRNG) — алгоритм, генерирующий последовательность чисел, элементы которой почти независимы друг от друга и подчиняются заданному распределению (обычно равномерному)." Wikipedia

 

Примерами генераторов могут служить Регистр сдвига с линейной обратной связью, Метод Фибоначчи с запаздываниями и «вихрь Мерсенна», предложенный в 1997 году Мацумото (松本 眞) и Нисимурой (西村 拓士).

 

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

 

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

До встречи на следующем уроке!

 

© Kirill. [email protected]

post-50854-1404216007,1488_thumb.jpg

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.

×