Доброго времени суток.
На прошлом уроке мы рассмотрели индикатор изнутри и сделали попытку создать свой первый рабочий код. Сегодня мы напишем информационный индикатор, который будет отображать основную информацию по торговому счету и текущему символу.
Для начала создадим в редакторе Meta Editor новый индикатор через сочетание клавиш Ctrl+N. Свойства индикатора трогать не будем, все остается по умолчанию. Дополнительных обработчиков событий добавлять не нужно, галочку «в отдельном окне» тоже не надо ставить. Сразу же введем внешнюю переменную типа double Max_Spread, а также на глобальном уровне переменную PipsDivided, равную единице, которая будет переводить значение спреда из новых пунктов в старые.
Тут хочется сделать небольшое отступление: примерно в 2010-х годах поставщики ликвидности и брокеры смогли предложить трейдерам новые счета, где у валютных пар появился пятый знак после запятой. С тех пор ходит постоянное недопонимание на форумах и блогах о том, как же правильно считать и прописывать эти пункты. Старички, включая меня и многие уважающие себя брокеры остановились на старом определении данных в 4х знаках, тогда как новички все считают уже в пятизнаке. Соответственно, когда старая гвардия говорит, что «цена прошла 20 пунктов», это значит, что цена прошла 20 старых пунктов, либо же 200 новых. То же самое и со спредом — если сказать, что спред составляет 2.5 пункта, что значит что он равняется 25 новым пунктам. Того же мнения я придерживаюсь в кодинге — пишу все параметры, связанные с пунктами в четырехзнаке, но добавляю проверку, где умножаю это значение на десять, если счет отображает цену в новых пунктах. Поэтому сейчас и в будущем, чтобы не возникло недопонимания, я буду указывать значения, связанные с пунктами только в 4х знаке, т.е. в старых пунктах.
Продолжим. Внешние параметры вводятся в самом вверху кода сразу после свойств программы. Создали переменную и в функции обработки событий OnInit умножаем ее значение на 10, если счет в новых пунктах. Количество знаков после запятой определяется через предопределенную переменную Digits. Соответственно, если у пары пять знаков после запятой, либо три (для пар с JPY), то счет в новых пунктах.
0 1 2 3 4 5 6 7 |
extern double Max_Spread = 5; int PipsDivided = 1; int OnInit() { if(Digits == 3 || Digits == 5) PipsDivided=10; return(INIT_SUCCEEDED); } |
Далее в функции OnCalculate повторим уже знакомый нам код из прошлого урока для расчета спреда:
0 1 |
double spr = NormalizeDouble(MarketInfo(Symbol(),MODE_SPREAD)/PipsDivided,1); string condition = (spr >= Max_Spread ? " - Too High!" : " - Normal"); |
Информацию на экран мы будем выдавать через Comment в верхнем левом углу экрана, потому что это самый простой способ. Для начала мы все данные запишем в функции OnCalculate в стринг переменную comm, а потом укажем ее в комменте.
0 |
string comm = "Информационный индикатор DaVinci FX"; |
Это первая строка, которая будет гласить название информационного списка. Чтобы сделать переход на новую строчку, необходимо добавить косую черту с буквой «\n «. С новой строки выведем название текущего символа, пусть он дублирует имя графика. Добавляем строчку в переменную comm:
0 1 2 |
string comm = "\n Информационный индикатор DaVinci FX" + "\n\n Символ: " + Symbol(); |
Соответственно, если поставить два раза знак переноса перед словом «Символ», то отступ будет на две строчки, что сейчас и нужно. После того, как строки прописаны, нужно поставить точку с запятой (;) в конце выражения. Теперь попробуйте вывести полученную информацию в коммент, написав ниже:
0 |
Comment(comm); |
Если все отображается, значит код написан корректно, закомментируем сейчас функцию Comment и продолжаем добавлять информацию в переменную comm. Проверим, разрешена ли вообще торговля по текущему инструменту:
0 |
+ "\n Разрешена ли торговля по валютной паре: " + (MarketInfo(Symbol(),MODE_TRADEALLOWED) ? "Да" : "Нет") |
Функция MarketInfo выдала нам информацию по рынку. Ее первым параметром мы указываем текущий символ. Второй, как раз отвечает за проверку разрешения на торговлю. В итоге данная функция возвращает true или false. Чтобы не плодить много строк, мы сразу же с помощью условного оператора ? сделали проверку и присвоили результатам текст «Да» и «Нет». В другом виде такая проверка выглядела бы так:
0 1 2 3 |
string result = ""; if(MarketInfo(Symbol(),MODE_TRADEALLOWED)) result = "Да"; else result = "Нет"; string comm2 = "\n Разрешена ли торговля по валютной паре: " + result; |
Так как краткость — сестра таланта, то мы не будет одну строку превращать в четыре. Этот пример не нужно добавлять в код.
Мы знаем, что у брокера бывают задержки при обновлении тиков, поэтому нужно знать время последнего тика вплоть до секунд:
0 |
+ "\n Последнее время обновления тика: " + TimeToString((datetime)MarketInfo(Symbol(),MODE_TIME),TIME_DATE|TIME_SECONDS) |
Данный код выглядит немного сумбурно из-за того, что MarketInfo возвращает значение типа double, время у нас должно быть в виде datetime, а комментарий в виде string. Поэтому тут присутствует двойное преобразование: вначале double в datetime, потом datetime в string.
В итоге на текущий момент содержание переменной comm должно выглядеть так:
0 1 2 3 4 |
string comm = "\n Информационный индикатор DaVinci FX" + "\n\n Символ: " + Symbol() + "\n Разрешена ли торговля по валютной паре: " + (MarketInfo(Symbol(),MODE_TRADEALLOWED) ? "Да" : "Нет") + "\n Последнее время обновления тика: " + TimeToString((datetime)MarketInfo(Symbol(),MODE_TIME),TIME_DATE|TIME_SECONDS); |
Продолжаем добавлять нужную для анализа информацию. Теперь не помешало бы отобразить данные по текущей цене. Так как указывать только цену Bid не совсем корректно, ведь покупки открываются по цене Ask, то укажем их обе:
0 1 |
+ "\n Цена Bid: " + DoubleToString(MarketInfo(Symbol(),MODE_BID),Digits) + "\n Цена Ask: " + DoubleToString(MarketInfo(Symbol(),MODE_ASK),Digits) |
Цена имеет тип данные double, поэтому с помощью функции DoubleToString мы ее переводим в текстовое значение, округляя значение до количества знаков после запятой данного символа Digits.
Раз есть цена, то нужно также не забыть и про спред, для которого в самом начале нами были введены переменные spr и condition:
0 |
+ "\n Спред: " + DoubleToString(spr,1) + condition |
Переходим на следующую строчку. Давайте рассчитаем самую низкую цену Low на графика, а также самую высокую High за текущий день:
0 1 |
+ "\n Цена Low D1: " + DoubleToString(iLow(Symbol(),PERIOD_D1,1),Digits) + "\n Цена High D1: " + DoubleToString(iHigh(Symbol(),PERIOD_D1,1),Digits) |
В наше время большинство брокеров отказалось от Стоп Левела и по умолчанию он равен нулю. Но, чтобы знать наверняка, введем проверку и на его значение:
0 |
+ "\n Размер Стоп Левела: " + (string)MarketInfo(Symbol(),MODE_STOPLEVEL) |
Данный блок завершен, поэтому добавляем знак перехода на новую строку, чтобы сделать разрыв между информацией:
0 |
+ "\n " |
Теперь давайте укажем размер пункта в валюте котировки, количество знаков после запятой и размер тика:
0 1 2 |
+ "\n Размер пункта: " + DoubleToString(MarketInfo(Symbol(),MODE_POINT),Digits) + "\n Знаков после запятой: " + DoubleToString(MarketInfo(Symbol(),MODE_DIGITS),0) + "\n Размер тика в валюте депозита: " + DoubleToString(MarketInfo(Symbol(),MODE_TICKVALUE),Digits) |
Не помешало бы еще знать значение свопа для покупок и продаж по текущему инстументу:
0 1 |
+ "\n Своп для покупок: " + DoubleToString(MarketInfo(Symbol(),MODE_SWAPLONG),2) + "\n Своп для продаж: " + DoubleToString(MarketInfo(Symbol(),MODE_SWAPSHORT),2); |
Закрываем этот блок, ставим точку с запятой в самом конце этого громоздкого текста. Прописываем комментарий, компилируем и кидаем индикатор на график, чтобы посмотреть, что же получилось. Если все работает, двигаемся дальше.
Чтобы немного усложнить задачу, мы введем два внешних параметра типа bool, с помощью которых пользователь будет вручную включать/выключать два будущих блока: «размер лота» и «количество ордеров».
0 1 |
extern bool ShowLotInfo = true; extern bool ShowOrdersInfo = true; |
Воспользуется условным оператором if для того, чтобы определить указанное значение переменной ShowLotInfo. И если значение true, то добавляем к уже созданной текстовой переменной comm дополнительный текст с помощью знака +=, который мы проходили в этом уроке.
0 |
if(ShowLotInfo == true) comm += "Наш текст" |
Как мы уже знаем, для проверки bool переменной не обязательно использовать операцию отношения и слова true/false. При false нужно просто перед переменной ShowLotInfo поставить знак (!).
Добавляем текст с расчетом значений максимального, минимального лота на данном торговом счете, а также минимальный шаг между его значениями:
0 1 2 3 |
if(ShowLotInfo == true) comm += "\n " + "\n Минимальный размер лота: " + DoubleToString(MarketInfo(Symbol(),MODE_MINLOT),2) + "\n Максимальный размер лота: " + DoubleToString(MarketInfo(Symbol(),MODE_MAXLOT),2) + "\n Шаг изменения размера лота: " + DoubleToString(MarketInfo(Symbol(),MODE_LOTSTEP),2); |
Соответственно, в положении true ShowLotInfo будет активен и расчет блока будет учитываться, а при false — нет. Так как в теле условного оператора только одна переменная comm, то фигурные скобки тут ставить не обязательно.
Остался последний блок расчета количества открытых ордеров на текущий момент, а также количества уже закрытых ордеров. Делаем проверку на переключатель ShowOrdersInfo и по аналогии с блоком выше прописываем текст:
0 1 2 |
if(ShowOrdersInfo) comm += "\n " + "\n Всего открытых ордеров: " + IntegerToString(OrdersTotal()) + "\n Всего закрытых ордеров: " + IntegerToString(OrdersHistoryTotal()); |
Функция OrdersTotal() выдает общее количество открытых и отложенных ордеров в терминале по всем символам. OrdersHistoryTotal() в свою очередь содержит в себе количество закрытых рыночных и удаленных отложенных ордеров, а также информацию по операциям с балансом: пополнение, вывод, начисление бонусов и т.д. Как фильтровать ордера из этой кучи и находить только нужные нам мы изучим в будущих уроках.
Количество ордеров всегда хранится в переменной целого типа и чтобы его перевести в текст, нужно воспользоваться функцией IntegerToString. Естественно, если вы этого не сделаете, то код все равно будет скомпилирован, но редактор выдаст вам предупреждение о некритических ошибках. Я же рекомендую всегда их исправлять, чтобы текст в окне Инструменты был: 0 errors, 0 warnings.
Все, думаю, что информации для отображения достаточно. Прописываем в конце функции OnCalculate Comment(comm). Осталось добавить функцию обработки событий OnDeinit, в которой единственной строчкой мы очистим всю информацию с экрана после того, как индикатор будет удален с графика.
0 1 2 3 |
void OnDeinit(const int reason) { Comment(""); } |
В итоге должен получиться вот такой код:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
//+------------------------------------------------------------------+ //| 2.1 Information indicator.mq4 | //| Copyright (c) DaVinci FX Group | //| https://www.davinci-fx.com/ | //+------------------------------------------------------------------+ #property copyright "Copyright (c) DaVinci FX Group" #property link "https://www.davinci-fx.com/" #property version "1.00" #property strict #property indicator_chart_window extern double Max_Spread = 5; extern bool ShowLotInfo = true; extern bool ShowOrdersInfo = true; int PipsDivided = 1; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { if(Digits == 3 || Digits == 5) PipsDivided=10; return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ void OnDeinit(const int reason) { Comment(""); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { double spr = NormalizeDouble(MarketInfo(Symbol(),MODE_SPREAD)/PipsDivided,1); string condition = (spr >= Max_Spread ? " - Too High!" : " - Normal"); string comm = "\n Информационный индикатор DaVinci FX" + "\n\n Символ: " + Symbol() + "\n Разрешена ли торговля по валютной паре: " + (MarketInfo(Symbol(),MODE_TRADEALLOWED) ? "Да" : "Нет") + "\n Последнее время обновления тика: " + TimeToString((datetime)MarketInfo(Symbol(),MODE_TIME),TIME_DATE|TIME_SECONDS) + "\n Цена Bid: " + DoubleToString(MarketInfo(Symbol(),MODE_BID),Digits) + "\n Цена Ask: " + DoubleToString(MarketInfo(Symbol(),MODE_ASK),Digits) + "\n Спред: " + DoubleToString(spr,1) + condition + "\n Цена Low D1: " + DoubleToString(iLow(Symbol(),PERIOD_D1,1),Digits) + "\n Цена High D1: " + DoubleToString(iHigh(Symbol(),PERIOD_D1,1),Digits) + "\n Размер Стоп Левела: " + (string)MarketInfo(Symbol(),MODE_STOPLEVEL) + "\n " + "\n Размер пункта: " + DoubleToString(MarketInfo(Symbol(),MODE_POINT),Digits) + "\n Знаков после запятой: " + DoubleToString(MarketInfo(Symbol(),MODE_DIGITS),0) + "\n Размер тика в валюте депозита: " + DoubleToString(MarketInfo(Symbol(),MODE_TICKVALUE),Digits) + "\n Своп для покупок: " + DoubleToString(MarketInfo(Symbol(),MODE_SWAPLONG),2) + "\n Своп для продаж: " + DoubleToString(MarketInfo(Symbol(),MODE_SWAPSHORT),2); if(ShowLotInfo == true) comm += "\n " + "\n Минимальный размер лота: " + DoubleToString(MarketInfo(Symbol(),MODE_MINLOT),2) + "\n Максимальный размер лота: " + DoubleToString(MarketInfo(Symbol(),MODE_MAXLOT),2) + "\n Шаг изменения размера лота: " + DoubleToString(MarketInfo(Symbol(),MODE_LOTSTEP),2); if(ShowOrdersInfo) comm += "\n " + "\n Всего открытых ордеров: " + IntegerToString(OrdersTotal()) + "\n Всего закрытых ордеров: " + IntegerToString(OrdersHistoryTotal()); Comment(comm); return(rates_total); } |
На графике это выглядит так:
Чуть больше информации я указал в скрипте нашей команды Terminal info script. Там данные отображаются в отдельном окне MessageBox для большего удобства. Думаю теперь вам не составит труда повторить его код самим. Недостающие идентификаторы запроса можно узнать из справки, установив курсор на тексте MarketInfo и нажав F1.
На сегодня все, надеюсь этот урок был для вас полезен.
[download url=»http://www.davinci-fx.com/wp-content/uploads/2021/01/2.1-Information-indicator.rar» title=»Скачать код индикатора»]