Ordermodify error 1 как исправить

Что значит ошибка с номером 1 при модификации ордера. Из операций предварительного сравнения цен перед проведением модификации ордера. Отсюда вывод - всегда нормализуйте цены в операциях сравнения. Точно Без нормализации вышеуказанный вариант тоже выдавал эту ошибку
//+------------------------------------------------------------------+
//|                                                   e-Trailing.mq4 |
//|                                           Ким Игорь В. aka KimIV |
//|                                              http://www.kimiv.ru |
//|                                                                  |
//| 12.09.2005 Автоматический Trailing Stop всех открытых позиций    |
//|            Вешать только на один график                          |
//+------------------------------------------------------------------+
#property copyright "Ким Игорь В. aka KimIV"
#property link      "http://www.kimiv.ru"
 
//------- Внешние параметры ------------------------------------------
extern bool   ProfitTrailing = True;  // Тралить только профит
extern int    TrailingStop   = 8;     // Фиксированный размер трала
extern int    TrailingStep   = 2;     // Шаг трала
extern bool   UseSound       = True;  // Использовать звуковой сигнал
extern string NameFileSound  = "expert.wav";  // Наименование звукового файла
 
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
void start() {
  for (int i=0; i<OrdersTotal(); i++) {
    if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
      TrailingPositions();
    }
  }
}
 
//+------------------------------------------------------------------+
//| Сопровождение позиции простым тралом                             |
//+------------------------------------------------------------------+
void TrailingPositions() {
  double pBid, pAsk, pp;
 
  pp = MarketInfo(OrderSymbol(), MODE_POINT);
  if (OrderType()==OP_BUY) {
    pBid = MarketInfo(OrderSymbol(), MODE_BID);
    if (!ProfitTrailing || (Bid-OrderOpenPrice())>TrailingStop*pp) {
      if (OrderStopLoss()<Bid-(TrailingStop+TrailingStep-1)*pp) {
        ModifyStopLoss(Bid-TrailingStop*pp);
        return;
      }
    }
  }
  if (OrderType()==OP_SELL) {
    pAsk = MarketInfo(OrderSymbol(), MODE_ASK);
    if (!ProfitTrailing || OrderOpenPrice()-Ask>TrailingStop*pp) {
      if (OrderStopLoss()>Ask+(TrailingStop+TrailingStep-1)*pp || OrderStopLoss()==0) {
        ModifyStopLoss(Ask+TrailingStop*pp);
        return;
      }
    }
  }
}
 
//+------------------------------------------------------------------+
//| Перенос уровня StopLoss                                          |
//| Параметры:                                                       |
//|   ldStopLoss - уровень StopLoss                                  |
//+------------------------------------------------------------------+
void ModifyStopLoss(double ldStopLoss) {
  bool fm;
 
  fm=OrderModify(OrderTicket(),OrderOpenPrice(),ldStopLoss,OrderTakeProfit(),0,CLR_NONE);
  if (fm && UseSound) PlaySound(NameFileSound);
}
//+------------------------------------------------------------------+

Я в своем эксперте для Чемпионата использовал Трал от Игоря
Кима, только везде (где только можно) добавил NormalizeDouble(), никаких
ошибок нет

Содержание

  1. Ошибка OrderModify ERROR 1 при изменения уровня стопа функцией трейлингстопа! Как исправить? — страница 3
  2. Ошибка OrderModify ERROR 1 при изменения уровня стопа функцией трейлингстопа! Как исправить? — страница 2
  3. Sashken! Тысяча спасибо Вам и Игорю Ким создавшему столь замечательный советник-трал!
  4. Modify error 1
  5. Ошибка #1 при модификации ордеров
  6. Ошибка модификации ордера(error 1)

Ошибка OrderModify ERROR 1 при изменения уровня стопа функцией трейлингстопа! Как исправить? — страница 3

rsi :
Рецепт простой: вместо

всё равно выдаёт ошибку 1

получается что if(.. || .. || ..) не срабатывает

и такое if((<> || <> )|| <>) тоже не срабатывает

всё равно выдаёт ошибку 1

получается что if(.. || .. || ..) не срабатывает

и такое if((<> || <> )|| <>) тоже не срабатывает

Не стОит проверять абсолютное равенсnво или неравенство чисел типа double . Поскольку мы имеем дело с ценами, которые имеют шаг Point, то, мы можем считать, что две цены равны, если абсолютная разность их значений меньше, скажем, чем 0.5*Point. Поэтому, оператор

правильно записать, как

Где переменную lvl следует определить выше, как, например:

что-то зациклились на этой ошибке..

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

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

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

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

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

изменившись в соответствии с реалиями, уровни стопа по факту могут быть стать теми же, что есть на момент изменения уровня и вуаля ошибка 1

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

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

Источник

Ошибка OrderModify ERROR 1 при изменения уровня стопа функцией трейлингстопа! Как исправить? — страница 2

Я в своем эксперте для Чемпионата использовал Трал от Игоря Кима, только везде (где только можно) добавил NormalizeDouble(), никаких ошибок нет

Sashken! Тысяча спасибо Вам и Игорю Ким создавшему столь замечательный советник-трал!

Читаем HELP.
Что значит ошибка с номером 1 при модификации ордера? Читаем:
ERR_NO_RESULT — OrderModify пытается изменить уже установленные значения такими же значениями. Необходимо изменить одно или несколько значений и повторить попытку.

Т.е. при «трале» Вы пытаетесь менять уровень стопа сам на себя. Откуда такое может быть? Из операций предварительного сравнения цен перед проведением модификации ордера!
Вы сравниваете ненормализованные цены и получаете результат — цены неравны. Пытаетесь произвести модификацию (при ней цены нормализуются принудительно) и получаете ответ что новая цена уже и так равна старой — менять нечего.
Отсюда вывод — всегда нормализуйте цены в операциях сравнения.

Точно:) Без нормализации вышеуказанный вариант тоже выдавал эту ошибку.

Читаем HELP.
Что значит ошибка с номером 1 при модификации ордера? Читаем:
ERR_NO_RESULT — OrderModify пытается изменить уже
установленные значения такими же значениями. Необходимо изменить одно или
несколько значений и повторить попытку.

Т.е. при «трале» Вы пытаетесь менять уровень стопа сам на себя. Откуда такое может быть? Из операций предварительного сравнения цен перед проведением модификации ордера!
Вы сравниваете ненормализованные цены и получаете результат — цены неравны. Пытаетесь произвести модификацию (при ней цены нормализуются принудительно) и получаете ответ что новая цена уже и так равна старой — менять нечего.
Отсюда вывод — всегда нормализуйте цены в операциях сравнения.

Читаем HELP.
Что значит ошибка с номером 1 при модификации ордера? Читаем:
ERR_NO_RESULT — OrderModify пытается изменить уже установленные значения такими же значениями. Необходимо изменить одно или несколько значений и повторить попытку.

Т.е. при «трале» Вы пытаетесь менять уровень стопа сам на себя. Откуда такое может быть? Из операций предварительного сравнения цен перед проведением модификации ордера!
Вы сравниваете ненормализованные цены и получаете результат — цены неравны. Пытаетесь произвести модификацию (при ней цены нормализуются принудительно) и получаете ответ что новая цена уже и так равна старой — менять нечего.
Отсюда вывод — всегда нормализуйте цены в операциях сравнения.

Источник

Modify error 1

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

Помогите с тралом плиииз.

Выдает OrderModify error 1 . Две первые сделки модифицирует, третья остается без стопа и сливает депо. Сделки все Buy

Добавлю: вторую сделку тралит правильно, но в какой-то момент OrderModify error 1 очень много раз потом Stack overflow. Видимо поэтому 3 сделка остается без стопа.

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

Правильно проверять так: два числа типа double не равны, если абсолютное значение их разности больше некоторого маленького числа. В вашем случае годится 0.5*Point.

Вторая ошибка связана с использованием ненормализованного числа в операторе OrderModify (). Правильно писать

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

с учетом приведенного выше предложения по сравнению двух чисел типа double .

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

Помогите с тралом плиииз.

Выдает OrderModify error 1 . Две первые сделки модифицирует, третья остается без стопа и сливает депо. Сделки все Buy

Добавлю: вторую сделку тралит правильно, но в какой-то момент OrderModify error 1 очень много раз потом Stack overflow. Видимо поэтому 3 сделка остается без стопа.

FxRoller :

А самое главное — не нужно осуществлять вызов функции из этой же самой функции. Возникает цикличность, которая и дает Stack overflow.

Если попытка модификации не удалась, не хотелось бы остаться без стопа.

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

не может же быть такого большого количества реквотов и т.п.

Если не рекурсия, то как это сделать?

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

Правильно проверять так: два числа типа double не равны, если абсолютное значение их разности больше некоторого маленького числа. В вашем случае годится 0.5*Point.

Вторая ошибка связана с использованием ненормализованного числа в операторе OrderModify (). Правильно писать

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

с учетом приведенного выше предложения по сравнению двух чисел типа double .

Источник

Ошибка #1 при модификации ордеров

Как убрать эту долбаную ошибку? Она меня уже достала. Проверяю каждый вводный параметр функции. У меня, в данный момент, это так:

Т.е. если параметр не изменён, то изменять его ненужно. Раньше я так не делал, но решил уж.

Дальше у меня параметры передаются в метода модификации ордера так:

Нв выходе в журнале:

Получается, журнал уведомил, типа модификация: ОК, а дальше. ошибка. Ни один параметр при этом не изменился.

Ордер отложенный. Так что менять можно цену открытия , стоп и тейк. И это, как я понимаю, не противоречил документации.

Кто сталкивался с подобным? Как решать?

Как убрать эту долбаную ошибку? Она меня уже достала. Проверяю каждый вводный параметр функции. У меня, в данный момент, это так:

Т.е. если параметр не изменён, то изменять его ненужно. Раньше я так не делал, но решил уж.

Дальше у меня параметры передаются в метода модификации ордера так:

Нв выходе в журнале:

Получается, журнал уведомил, типа модификация: ОК, а дальше. ошибка. Ни один параметр при этом не изменился.

Ордер отложенный. Так что менять можно цену открытия, стоп и тейк. И это, как я понимаю, не противоречил документации.

Кто сталкивался с подобным? Как решать?

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

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

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

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

А может ещё и массив ошибок завести? Ведь в документации чёрным по белому написано, что переменная _LastError хранит номер последней ошибки. А сброс её производится функцией ResetLastError(). Если между вызовами _LastError не было ошибок больше, то _LastError хранит значение последней ошибки . У меня по ходу кода больше не было ошибок. А значится, вопрос не в этом.

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

Ведь если есть переменная для сбора ошибок, то зачем их плодить?

Источник

Ошибка модификации ордера(error 1)

Вроде все по уроку делал, может что пропустил?

//| Copyright 2016, MetaQuotes Software Corp. |

#property copyright «Copyright 2016, MetaQuotes Software Corp.»

#property link «https://www.mql5.com»

#property version «1.00»

extern double Lots = 0.1;

extern int TakeProfit = 30;

extern int Step = 50;

extern double Multipler = 2;

extern int Magic = 123;

//extern int tframe = 60;

extern int period = 14;

extern int Slippage = 3;

double tp, price, lastlot;

//| Expert initialization function |

if (Digits == 3 || Digits == 5)

//| Expert deinitialization function |

void OnDeinit(const int reason)

//| Expert tick function |

double ima = iMA(Symbol(), 0, period, 0, MODE_SMA, PRICE_CLOSE, 0);

if (CountTrades() == 0)

tp = NormalizeDouble(Ask + TakeProfit*Point, Digits);

ticket = OrderSend(Symbol(), OP_BUY, Lots, Ask, Slippage, 0, tp, «», Magic, 0, Blue);

tp = NormalizeDouble(Bid — TakeProfit*Point, Digits);

ticket = OrderSend(Symbol(), OP_SELL, Lots, Bid, Slippage, 0, tp, «», Magic, 0, Red);

int order_type = FindLastOrderType();

if(Ask = price + Step*Point)

lastlot = NormalizeDouble(lastlot * Multipler, 2);

ticket = OrderSend(Symbol(), OP_SELL, lastlot, Bid, Slippage, 0, 0, «», Magic, 0, Red);

if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES))

if (OrderSymbol() == Symbol() && OrderMagicNumber() == Magic && OrderType() == otype)

price += OrderOpenPrice() * OrderLots();

avg_price = NormalizeDouble(price / order_lots, Digits);

if (otype == OP_BUY) tp = NormalizeDouble(avg_price + TakeProfit*Point, Digits);

if (otype == OP_SELL) tp = NormalizeDouble(avg_price — TakeProfit*Point, Digits);

for (int i = OrdersTotal()-1; i>=0; i—)

if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES))

if (OrderSymbol() == Symbol() && OrderMagicNumber() == Magic && OrderType() == otype)

if(OrderModify(OrderTicket(), OrderOpenPrice(), 0, tp, 0))

Print(«Ордера успешно модифицированны»);

else Print(«Ошибка модификации ордеров»);

double FindLastLots(int otype)

for(int cnt = OrdersTotal()-1; cnt>=0; cnt—)

if(OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES))

if (OrderSymbol() == Symbol() && OrderMagicNumber() == Magic && OrderType() == otype)

if (oldticket > ticket)

for(int i=OrdersTotal()-1; i>=0;i—)

if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))

if (OrderSymbol() == Symbol() && OrderMagicNumber() == Magic)

if (OrderType() == OP_BUY || OrderType() == OP_SELL)

for(int i = OrdersTotal()-1; i>=0; i—)

if (OrderSymbol() == Symbol() && OrderMagicNumber() == Magic)

double FindLastOrderPrice(int otype)

for(int cnt = OrdersTotal()-1; cnt>=0; cnt—)

if(OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES))

if (OrderSymbol() == Symbol() && OrderMagicNumber() == Magic && OrderType() == otype)

Источник

Разработка торговых экспертов на языке MQL4 является не такой уж простой задачей. Во-первых – алгоритмизация любой сложной торговой системы уже представляет собой проблему, так как нужно учесть очень много деталей, начиная с особенностей ТС и заканчивая спецификой среды MetaTrader 4. Во-вторых, даже наличие детальнейшего алгоритма не избавляет от сложностей, возникающих при переносе разработанного алгоритма на язык программирования MQL4.

Компилятор оказывает некоторую помощь при написании корректных экспертов. После начала компиляции MetaEditor сообщит обо всех синтаксических ошибках в вашем коде. Но, к сожалению, помимо синтаксических ошибок ваш советник может содержать еще и логические ошибки, которые компилятор выловить не может. Поэтому этим нам придется заняться самим. Как это сделать – в нашем сегодняшнем материале.

MQL4 — Ошибки и как их исправить

Самые распространенные ошибки компиляции

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

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

Идентификатор совпадает с зарезервированным словом

Если наименование переменной или функции совпадает с одним из зарезервированных слов:

int char[];  // неправильно
int char1[]; // правильно
int char()   // неправильно
{
    return(0);
}

то компилятор выводит сообщения об ошибках:

Для исправления данной ошибки нужно исправить имя переменной или функции. Я рекомендую придерживаться следующей системы для именования:

Все функции должны обозначать действие. То есть это должен быть глагол. Например, OpenLongPosition() или ModifyStopLoss(). Ведь функции всегда именно что-то делают, верно?

Кроме того, функции желательно называть в так называемом CamelCase стиле. А переменные в cebab_case стиле. Это общепринятая практика.

Кстати, об именах переменных. Переменные – это существительные. Например, my_stop_loss, day_of_week, current_month. Не так страшно назвать переменную длинным именем, гораздо страшнее назвать ее непонятно. Что такое dow, индекс Dow Jones? Нет, это, оказывается, день недели. Конечно, сегодня вам и так понятно, что это за переменная. Но когда вы откроете код советника месяц спустя, все будет уже не так явно. А это время, упущенное на расшифровку посланий из прошлого – оно вам надо?

Специальные символы в наименованиях переменных и функций

Идем дальше. Если наименования переменных или функций содержат специальные символы ($, @, точка):

int $var1; // неправильно
int @var2; // неправильно
int var.3; // неправильно
void f@()  // неправильно
{
    return;
}

то компилятор выводит сообщения об ошибках:

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

Ошибки использования оператора switch

Старая версия компилятора позволяла использовать любые значения в выражениях и константах оператора switch:

void start()
{
    double n=3.14;
    switch(n)
    {
        case 3.14: 
            Print("Pi");
            break;
        case 2.7: 
            Print("E");
            break;
    }
}

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

Поэтому, когда вы разбираете код классики, такой, как WallStreet, Ilan и прочей нетленки (что очень полезно для саморазвития), можно натолкнуться на эту ошибку. Лечится она очень просто, например, при использовании такой вот строки:

switch(MathMod(day_48, 10))

Вот так можно запросто решить проблему:

switch((int)MathMod(day_48, 10))

Возвращаемые значений функций

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

При строгом режиме компиляции (strict) возникает ошибка:

В режиме компиляции по умолчанию компилятор выводит предупреждение:

Если возвращаемое значение функции не соответствует объявлению:

Тогда при строгом режиме компиляции возникает ошибка:

В режиме компиляции по умолчанию компилятор выводит предупреждение:

Для исправления таких ошибок в код функции всего-навсего нужно добавить оператор возврата return c возвращаемым значением соответствующего типа.

Массивы в аргументах функций

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

double ArrayAverage(double a[])
{
    return(0);
}

Данный код при строгом режиме компиляции (strict) приведет к ошибке:

В режиме компиляции по умолчанию компилятор выводит предупреждение:

Для исправления таких ошибок нужно явно указать передачу массива по ссылке, добавив префикс & перед именем массива:

double ArrayAverage(double &a[])
{
    return(0);
}

Кстати, константные массивы (Time[], Open[], High[], Low[], Close[], Volume[]) не могут быть переданы по ссылке. Например, вызов:

вне зависимости от режима компиляции приводит к ошибке:

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

//--- массив для хранения значений цен открытия
double OpenPrices[];
//--- копируем значения цен открытия в массив OpenPrices[]
ArrayCopy(OpenPrices,Open,0,0,WHOLE_ARRAY);
//--- вызываем функцию
ArrayAverage(OpenPrices);

Одна из самых распространенных ошибок – потеря советником индикатора. В таких случаях обычно пользователи эксперта на форумах гневно пишут: «Советник не работает!» или «Ставлю советник на график и ничего не происходит!». Решение этого вопроса на самом деле очень простое. Как всегда, достаточно просто заглянуть на вкладку «Журнал» терминала и обнаружить там запись вроде:

2018.07.08 09:15:44.957 2016.01.04 00:51 cannot open file 
'C:Users1AppDataRoamingMetaQuotesTerminal
MQL4indicatorsKELTNER_F12.ex4' [2]

Говорит это нам о том, что индикатор в папку положить забыли, или же он назван по-другому. Если индикатор отсутствует, нужно добавить его в папку с индикаторами. Если он есть, стоит проверить его название в коде советника – скорее всего там он называется по-другому.

Предупреждения компилятора

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

Пересечения имен глобальных и локальных переменных

Если на глобальном и локальном уровнях присутствуют переменные с одинаковыми именами:

int i; // глобальная переменная
void OnStart()
{
    int i=0,j=0; // локальные переменные

    for (i=0; i<5; i++) {
        j+=i;
    }
    PrintFormat("i=%d, j=%d",i,j);
}

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

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

Несоответствие типов

В следующем примере:

#property strict
void OnStart()
{
    double a=7;
    float b=a;
    int c=b;
    string str=c;
    Print(c);
}

при строгом режиме компиляции при несоответствии типов компилятор выводит предупреждения:

В данном примере компилятор предупреждает о возможной потере точности при присвоении различных типов данных и неявном преобразовании типа int в string.

Для исправления нужно использовать явное приведение типов:

#property strict
void OnStart()
{
    double a=7;
    float b=(float)a;
    int c=(int)b;
    string str=(string)c;
    Print(c);
}

Неиспользуемые переменные

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

void OnStart()
{
    int i,j=10,k,l,m,n2=1;
    for(i=0; i<5; i++) {j+=i;}
}

Сообщения о таких переменных выводятся вне зависимости от режима компиляции:

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

Диагностика ошибок при компиляции

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

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

Написать достаточно большой код без единой ошибки – очень приятно. Но, к сожалению, так получается не часто. Я не рассматриваю здесь ошибки, которые приводят к неверному исполнению кода. Здесь пойдёт речь об ошибках, из-за которых становится невозможной компиляция.

Весьма распространённые ошибки – вставка лишней скобки в сложном условии, нехватка скобки, не выставление двоеточия, запятой при объявлении переменных, опечатка в названии переменной и так далее. Часто при компиляции можно сразу увидеть, в какой строке допущена подобная ошибка. Но бывают и случаи, когда найти такую ошибку не так просто. Ни компилятор, ни зоркий глаз нам не могут помочь сразу найти ошибку. В таких случаях, как правило, начинающие программисты начинают “обходить” весь код, пытаясь визуально определить ошибку. И снова, и снова, пока выдерживают нервы.

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

Поиск ошибок обычно сводится к определению участка кода, где допущена ошибка, а затем, в этом участке, визуально находится ошибка. Думаю, вряд ли кто-то будет сомневаться в том, что исследовать “на глаз” 5-10 строчек кода проще и быстрей, чем 100-500, а то и несколько тысяч.

При использовании комментирования задача предельно проста. Сначала нужно закомментировать различные участки кода (иногда чуть ли не весь код), тем самым “отключив” его. Затем, по очереди, комментирование снимается с этих участков кода. После очередного снятия комментирования совершается попытка компиляции. Если компиляция прошла успешно – ошибка не в этом участке кода. Затем открывается следующий участок кода и так далее. Когда находится проблемный участок кода, визуально ищется ошибка, затем устраняется. Опять происходит попытка компиляции. Если всё прошло успешно, ошибка устранена.

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

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

Ошибки времени выполнения

Ошибки, возникающие в процессе исполнения кода программы, принято называть ошибками времени выполнения (runtime errors). Такие ошибки обычно зависят от состояния программы и связаны с некорректными значениями переменных.

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

Выход за пределы массива (Array out of range)

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

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

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+

int start()
{
    //--- иногда для расчета требуется не менее N баров (например, 100)
    // если на графике нет такого количества баров (например, на таймфрейме MN)
    if (Bars<100) {
        return(-1); // прекращаем расчет и выходим досрочно
    }

    //--- количество баров, не изменившихся с момента последнего вызова индикатора
    int counted_bars=IndicatorCounted();
    //--- в случае ошибки выходим
    if (counted_bars<0) {
        return(-1);
    }
    //--- позиция бара, с которого начинается расчет в цикле
    int limit=Bars-counted_bars;

    //--- если counted_bars=0, то начальную позицию в цикле нужно уменьшить на 1,
    if (counted_bars==0) {
        limit--;  // чтобы не выйти за пределы массива при counted_bars==0
        //--- в расчетах используется смещение на 10 баров вглубь 
        //--- истории, поэтому добавим это смещение при первом расчете
        limit-=10;
    } else {
        //--- индикатор уже рассчитывался ранее, counted_bars>0
        //--- при повторных вызовах увеличим limit на 1, чтобы 
        //--- гарантированно обновлять значения индикатора для последнего бара
        limit++;
    }
    //--- основной цикл расчета
    for (int i=limit; i>0; i--) {
        // используются значения баров, уходящих вглубь истории на 5 и 10
        Buff1[i]=0.5*(Open[i+5]+Close[i+10]) 
    }
}

Часто встречается некорректная обработка случая counted_bars==0 (начальную позицию limit нужно уменьшить на значение, равное 1 + максимальный индекс относительно переменной цикла).

Также следует помнить о том, что в момент исполнения функции start() мы можем обращаться к элементам массивов индикаторных буферов от 0 до Bars()-1. Если есть необходимость работы с массивами, которые не являются индикаторными буферами, то их размер следует увеличить при помощи функции ArrayResize() в соответствии с текущим размером индикаторных буферов. Максимальный индекс элемента для адресации также можно получить вызовом ArraySize() с одним из индикаторных буферов в качестве аргумента.

Деление на ноль (Zero divide)

Ошибка “Zero divide” возникает в случае, если при выполнении операции деления делитель оказывается равен нулю:

void OnStart()
{
    int a=0, b=0,c;
    c=a/b;
    Print("c=",c);
}

При выполнении данного скрипта во вкладке “Эксперты” возникает сообщение об ошибке и завершении работы программы:

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

Самый простой способ – проверять делитель перед операцией деления и выводить сообщение о некорректном значении параметра:

void OnStart()
{
    int a=0, b=0,c;
    if (b!=0) {
        c=a/b; Print(c);
    } else {
        Print("Error: b=0"); 
        return; 
    }
}

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

Использование 0 вместо NULL для текущего символа

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

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

AlligatorJawsBuffer[i]=iMA(0,0,13,8,MODE_SMMA,PRICE_MEDIAN,i);    // неправильно

В новом компиляторе для указания текущего символа нужно явно указывать NULL:

AlligatorJawsBuffer[i]=iMA(NULL,0,13,8,MODE_SMMA,PRICE_MEDIAN,i); // правильно

Кроме того, текущий символ и период графика можно указать при помощи функций Symbol() и Period().

AlligatorJawsBuffer[i]=iMA(Symbol(),Period(),13,8,MODE_SMMA,PRICE_MEDIAN,i); // правильно

Еще лучше, если вы будете использовать предопределенные переменные _Symbol и _Period – они обрабатываются быстрее:

AlligatorJawsBuffer[i]=iMA(_Symbol,_Period,13,8,MODE_SMMA,PRICE_MEDIAN,i); // правильно

Строки в формате Unicodе и их использование в DLL

Строки представляют собой последовательность символов Unicode. Следует учитывать этот факт и использовать соответствующие функции Windows. Например, при использовании функций библиотеки wininet.dll вместо InternetOpenA() и InternetOpenUrlA() следует вызывать InternetOpenW() и InternetOpenUrlW(). При передаче строк в DLL следует использовать структуру MqlString:

#pragma pack(push,1)
struct MqlString
{
    int      size;       // 32-битное целое, содержит размер распределенного для строки буфера
    LPWSTR   buffer;     // 32-разрядный адрес буфера, содержащего строку
    int      reserved;   // 32-битное целое, зарезервировано, не использовать
};
#pragma pack(pop,1)

Совместное использование файлов

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

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

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

// 1-st change - add share flags
ExtHandle=FileOpenHistory(c_symbol+i_period+".hst",
    FILE_BIN|FILE_WRITE|FILE_SHARE_WRITE|FILE_SHARE_READ);

Особенность преобразования datetime

Следует иметь ввиду, что преобразование типа datetime в строку зависит от режима компиляции:

datetime date=D'2014.03.05 15:46:58';
string str="mydate="+date;
//--- str="mydate=1394034418" - без директивы #property strict
//--- str="mydate=2014.03.05 15:46:58" - с директивой #property strict

Например, попытка работы с файлами, имя которых содержит двоеточие, приведет к ошибке.

Обработка ошибок времени выполнения

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

В наборе “из коробки” доступны некоторые библиотеки для упрощения написания советников, в том числе и для работы с ошибками. Хранятся они в папке MQL4/Include:

Нам понадобятся две библиотеки:

  • stderror.mqh – содержит константы для номера каждой ошибки;
  • stdlib.mqh – содержит несколько вспомогательных функций, в том числе и функцию возврата описания ошибки в виде строки:
string ErrorDescription(int error_code)

Поэтому подключим в наш проект обе эти библиотеки:

#include <stderror.mqh>
#include <stdlib.mqh>

Сами описания ошибок находятся в файле MQL4/Library/stdlib.mql4 и они на английском языке. Поэтому, если вы против иностранных языков, всегда можно переписать описания на свой родной.

Еще одна встроенная необходимая нам функция – GetLastError(). Именно она возвращает коды ошибок в виде целого числа (int), который мы потом будем обрабатывать. Сами коды ошибок и их описания на русском можно посмотреть в руководстве по mql4 от MetaQuotes. Оттуда же можно взять информацию для перевода файла stdlib.mql4 на русский.

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

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

Рассмотрим для примера две типичные для экспертов на MQL4 ошибки:

  1. Ошибка 130 – ERR_INVALID_STOPS
  2. Ошибка 146 – ERR_TRADE_CONTEXT_BUSY

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

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

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

void logError(string functionName, string msg, int errorCode = -1)
{
    Print("ERROR: in " + functionName + "()");
    Print("ERROR: " + msg );

    int err = GetLastError();

    if (errorCode != -1) {
        err = errorCode;
    }

    if (err != ERR_NO_ERROR) {
        Print("ERROR: code=" + err + " - " + ErrorDescription( err ));
    }
}

Использовать ее мы будем следующим образом:

void openLongTrade()
{
    int ticket = OrderSend(Symbol(), OP_BUY, 1.0, Ask + 5, 5, 0, 0);
    if (ticket == -1) {
        logError("openLongTrade", "could not open order");
    }
}

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

Первым параметром в функцию logError() передается имя функции, в которой была обнаружена ошибка, в нашем примере – в функции openLongTrade(). Если наш эксперт вызывает функцию OrderSend() в нескольких местах, это позволит нам точно установить, в каком из них произошла ошибка. Вторым параметром передается описание ошибки, чтобы можно было понять, где именно внутри функции openLongTrade() была обнаружена ошибка. Это может быть как краткое описание ошибки, так и более развернутое, с перечислением значений всех параметров, переданных во встроенную функцию.

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

ERROR: in openLongTrade()
ERROR: could not open order
ERROR: code=138 - requote

То есть сразу будет видно:

  • в какой функции произошла ошибка;
  • к чему она относится (в данном случае – к попытке открыть позицию);
  • какая именно ошибка возникла (код ошибки и ее описание).

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

void updateStopLoss(double newStopLoss)
{
    bool modified = OrderModify(OrderTicket(), OrderOpenPrice(), 
        newStopLoss, OrderTakeProfit(), OrderExpiration());
    if (!modified) {
        int errorCode = GetLastError();
        if (errorCode != ERR_NO_RESULT ) {
            logError("updateStopLoss", "failed to modify order", errorCode);
        }
    }
}

Здесь в функции updateStopLoss() вызывается встроенная функция OrderModify(). Эта функция несколько отличается в плане обработки ошибок от OrderSend(). Если ни один из параметров изменяемого ордера не отличается от его текущих параметров, то функция вернет ошибку ERR_NO_RESULT. Если в нашем эксперте такая ситуация допустима, то мы должны игнорировать конкретно эту ошибку. Для этого мы анализируем значение, возвращаемое GetLastError(). Если произошла ошибка с кодом ERR_NO_RESULT, то мы ничего не выводим в протокол.

Однако если произошла другая ошибка, то необходимо полностью отрапортовать о ней, как мы делали это раньше. Именно для этого мы сохраняем результат функции GetLastError() в промежуточной переменной и передаем его третьим параметром в функцию logError(). Дело в том, что встроенная функция GetLastError() автоматически обнуляет код последней ошибки после своего вызова. Если бы мы не передали код ошибки явно в logError(), то в протоколе была бы отражена ошибка с кодом 0 и описанием “no error”.

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

Диагностика логических ошибок

Логические ошибки в коде эксперта могут доставить много проблем. Отсутствие возможности пошаговой отладки экспертов делают борьбу с такими ошибками не очень приятным занятием. Основным средством для диагностики этого на данный момент является встроенная функция Print(). С ее помощью можно выполнять распечатку текущих значений важных переменных, а также протоколировать ход работы эксперта прямо в терминале во время тестирования. При отладке эксперта во время тестирования с визуализацией также может помочь встроенная функция Comment(), которая выводит сообщения на график. Как правило, убедившись, что эксперт работает не так, как было задумано, приходится добавлять временные вызовы функции Print() и протоколировать внутреннее состояние эксперта в предполагаемых местах возникновения ошибки.

Однако, для обнаружения сложных ошибочных ситуаций порой приходится добавлять десятки таких вызовов функции Print(), а после обнаружения и устранения проблемы их приходится удалять или комментировать, чтобы не загромождался код эксперта и не замедлялось его тестирование. Ситуация ухудшается, если в коде эксперта функция Print() уже используется для периодического протоколирования различных состояний. Тогда удаление временных вызовов Print() не удается выполнить путем простого поиска фразы ‘Print’ в коде эксперта. Приходится задумываться, чтобы не удалить еще и полезные вызовы этой функции.

Например, при протоколировании ошибок функций OrderSend(), OrderModify() и OrderClose() полезным бывает печатать в протокол текущее значение переменных Bid и Ask. Это несколько облегчает распознавание причин таких ошибок, как ERR_INVALID_STOPS и ERR_OFF_QUOTES.

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

void logInfo(string msg)
{
    Print("INFO: " + msg);
}

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

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

void openLongTrade(double stopLoss)
{
    int ticket = OrderSend(Symbol(), OP_BUY, 1.0, Ask, 5, stopLoss, 0);
    if (ticket == -1) {
        logError("openLongTrade", "could not open order");
    }
}

В данном случае, так как мы открываем длинную позицию, совершенно очевидно, что при нормальной работе эксперта значение параметра stopLoss никогда не будет больше или равно текущей цене Bid. То есть, при вызове функции openLongTrade() всегда выполняется условие stopLoss < Bid. Так как мы знаем об этом еще на этапе написания рассматриваемой функции, то мы сразу же можем этим воспользоваться следующим образом:

void openLongTrade( double stopLoss )
{
    assert("openLongTrade", stopLoss < Bid, "stopLoss < Bid");
 
    int ticket = OrderSend(Symbol(), OP_BUY, 1.0, Ask, 5, stopLoss, 0);
    if (ticket == -1) {
        logError("openLongTrade", "could not open order");
    }
}

То есть мы логируем наше утверждение в коде при помощи новой вспомогательной функции assert(). Сама функция выглядит довольно просто:

void assert(string functionName, bool assertion, string description = "")
{
    if (!assertion) {
        Print("ASSERT: in " + functionName + "() - " + description);
    }
}

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

  • название функции, в которой условие было нарушено;
  • описание нарушенного условия.

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

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

Еще одним полезным приемом является использование этой функции перед каждой операцией деления. Дело в том, что иногда в результате той или иной логической ошибки иногда происходит деление на ноль. Работа эксперта в этом случае прекращается, а в протоколе появляется одна лишь строка с печальным диагнозом: ‘zero divide’. Узнать, в каком именно месте произошла эта ошибка, если операция деления используется в коде неоднократно, достаточно сложно. Вот здесь и поможет функция assert(). Вставляем соответствующие проверки перед каждой операцией деления:

assert("buildChannel", distance > 0, "distance > 0");
double slope = delta / distance;

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

Обработка состояний

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

Функция IsExpertEnabled() возвращает информацию о возможности запуска экспертов. Функция вернет true, если в клиентском терминале разрешен запуск экспертов, иначе возвращает false. В случае возврата false полезно будет известить об этом пользователя с просьбой включить соответствующую настройку. Пример:

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

Если эксперт использует внешние библиотеки, пригодится функция IsLibrariesAllowed(). Она возвращает true, если эксперт может вызвать библиотечную функцию, иначе возвращает false.

Если библиотека в виде dll файла, пригодится функция IsDllsAllowed(). Также нелишним будет проверить, есть ли вообще возможность торговать при помощи экспертов с помощью функции IsTradeAllowed().

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

Все вышеперечисленные проверки стоит сделать в функции OnInit().

Конечно же, стоит проверять периодически связь с сервером. В этом поможет функция IsConnected().

Следующие три функции помогут определить, в каком режиме находится советник. Если IsOptimisation() возвращает true, проводится оптимизация, если IsTesting(), то тестирование, IsVisualMode() – тестирование в режиме визуализации. Под каждый из этих вариантов в советнике может быть предусмотрена своя логика. Например, для режима визуализации можно что-то выводить на график (и не выводить в других режимах ради экономии ресурсов). В режиме тестирования можно выводить отладочную информацию, в режиме оптимизации максимально облегчить код, чтобы сэкономить время.

И последняя функция – IsTradeContextBusy(). Она вернет true, если поток для выполнения торговых операций занят. Это бывает полезно при совершении экспертом торговых операций. Можно применить функцию Sleep для ожидания некоторого момента и новой попытки.

Еще одна полезная функция – 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;  // подготовка к рестарту.
    }
    //...
}

Можно также логировать причину выхода советника.

Коды самых распространенных ошибок и их вероятное решение

№ ошибки Значение Проблема Решение
4, 146 Торговый сервер занят Советник подал слишком много приказов одновременно или не дождавшись ответа от сервера, при выполнении операции – советник пытается отправить новый приказ Перезагрузка терминала или оптимизация кода советника с помощью функций обработки ошибок
8, 141 Слишком частые запросы Предыдущие причины ошибки, в сильно частом запросе Аналогичное решение
129 Неправильная цена Цена по которой Вы пытаетесь открыть позицию (BUY или SELL) неправильная BUY нужно открывать по Ask а закрывать по BID;
SELL нужно открывать по BID а закрывать по ASK
130, 145 Неправильные стопы Стоп лосс, тейк профит или уровень открытия отложки или лимитника неверные.
Стопы расположены слишком близко к цене.
Ваш счет открыт в группе ECN (ЕЦН) или NDD (НДД), что не дает сразу выставлять стопы
Проверьте значения Ваших стоп лоссов, тейк профитов, уточните минимальный стоп уровень по Вашему инструменту у брокера, при выставлении стопов – соблюдайте уровень минимальной дистанции. В хорошо написанном советнике должны быть функции работы на счетах ECN и NDD – это происходит путем модификации ордера уже после его открытия
131 Неправильный объем Неправильный лот при открытии сделки, или меньше минимального (больше максимального). Разрядность лота тоже может отличаться от разрядности брокера Проверьте правильность открытия лота, изучите спецификацию контракта и прочтите условия торговли в Вашем ДЦ, проверьте минимальный и максимальный лот в Вашем ДЦ и на Вашем счете
132 Рынок закрыт Рынок закрыт на выходные дни Пробуйте связаться с рынком после выходных
133 Торговля запрещена В данный момент торговля запрещена По данной валютной паре запрещено торговать – в конкретный момент времени или вообще. Часто у брокеров есть перерыв в несколько минут в полночь
134 Недостаточно денег для совершения операции Лот, который Вы пытаетесь открыть, слишком большой, на него не хватает маржи Проверьте уровень свободных средств и рассчитайте средства, которые Вам нужны для открытия лота, следите за уровнем Ваших свободных средств
135-138 Цена изменилась Реквот, слишком быстрый рынок (новости), Брокер или ДЦ не дает Вам поставить позицию по заявленной цене Не торгуйте в такие моменты, увеличьте уровень проскальзывания, но помните, что это влечет за собой открытие позиций не по заявленной Вами цене. Предусмотрите в советнике функцию обработки ошибок и количество попыток открытия позиций
147 Использование даты истечения ордера запрещено брокером Ваш советник или Вы пытаетесь установить срок истечения отложенного ордера В советнике, в функции OrderSend в параметре срок истечения поставьте 0 (ноль). Не устанавливайте срок истечения ордера
148 Количество открытых и отложенных ордеров достигло предела, установленного брокером Максимальное количество открытых ордеров и позиций достигло предела, установленного брокером Удалите или закройте часть позиций. Остановите процесс открытия новых позиций
4012, 4013 Остаток от деления на ноль Вы пытаетесь поделить число на 0 (ноль) Проверьте код советника на наличие ошибки, или же проверьте все значения из MarketInfo функций на момент возвращения 0, иногда при MarketInfo(Symbol(),MODE_SPREAD) возвращается не спред, а 0 (у брокеров с плавающим спредом)
4017 Вызовы DLL не разрешены В Вашем терминале запрещен вызов DLL Разрешите вызов DLL через Меню – сервис – Настройки – Советник – Разрешить вызов DLL
4018, 4019 Невозможно загрузить библиотеку Библиотека повреждена или ее вызов завершается с ошибкой, возможно она вообще отсутствует Проверьте библиотеку DLL
4020 Вызовы внешних библиотечных функций не разрешены В Вашем терминале запрещен вызов функций из внешних экспертов Разрешите вызов функций через Меню – сервис – Настройки – Советник – Разрешить вызов внешних экспертов
4103 Невозможно открыть файл Данный файл не существует или заблокирован другим процессом Проверьте наличие указанного файла. Проверьте, не заблокирован ли файл системой антивируса, разрешен ли режим записи-чтения файла
4106 Неизвестный символ Символа нет в обзоре рынка В обзоре рынка – правой кнопкой мыши – показать все символы. Проверить названия символа в советнике и наличие его в обзоре рынка. Некоторые советники используют четкие названия без суффиксов, а брокеры намеренно ставят суффиксы, например EURUSDx где х – суффикс
4108 Неверный номер тикета Тикет ордера, который выбирает эксперт – не существует. Эксперт пытается выбрать тикет, но данный ордер был закрыт другим советником или руками. При попытке осуществления приказа над ордером, тикет был исполнен и закрыт брокером Если данная ошибка появляется очень часто, 100-1000 раз за минуту, проверьте функции Вашего советника. Отключите другие советники или настройте их так, чтобы они не конфликтовали, не закрывайте ордер руками, когда эксперт выполняет операцию. Иногда такое случается, когда несколько советников используют одинаковый MagicNumber
4109 Торговля не разрешена Советнику запрещено торговать, на графике грустный смайл или крестик Включите галочку «Разрешить советнику торговать» во вкладе при установке советника, либо в меню – сервис – настройки – советники
4110, 4111 Длинные/короткие позиции не разрешены В настройках советника, во вкладке Общие не разрешен тип позиций Во вкладке Общие, при установке советника, есть выбор позиций, разрешенных к открытию

Заключение

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

Тема на форуме

С уважением, Дмитрий аkа Silentspec
TradeLikeaPro.ru

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

Как вы знаете ECN/STP-брокеры, которые используют MetaTrader, не поддерживают установку стоп-лосса и тейк-профита при открытии сделки. В этом случае нам нужно будет разместить стоп-лосс и тейк-профит после размещения ордера с помощью функции OrderModify(). Это относится только к рыночным ордерам — для отложенных ордеров вы все равно можете разместить стоп-лосс и тейк-профит с помощью функции OrderSend().

Рассмотрим синтаксис функции:

bool  OrderModify(
   int        ticket,      // номер ордера
   double     price,       // цена открытия
   double     stoploss,    // stop loss
   double     takeprofit,  // take profit
   datetime   expiration,  // время истечения ордера
   color      arrow_color  // цвет
   );

Ее параметры:

  • ticket — для идентификации тикета ордера.
  • price — используется для изменения цены открытия отложенного ордера.
  • stoploss — новая цена для стоп-лосса.
  • takeprofit — новая цена для тейк-профита.
  • expiration — изменить время истечения отложенных ордеров.
  • arrow_color — изменить цвет стрелки на графике.

Если изменение ордера выполнено успешно, OrderModify() вернет значение true. Если произошла ошибка, возвращаемое значение будет ложным.

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

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

Почему нам может быть необходимо изменить ордер? Вот несколько примеров:

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

Как добавить стоп-лосс и тейк-профит в существующий ордер?

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

Затем мы используем функцию OrderSelect(), чтобы получить информацию о только что размещенном ордере. Мы будем использовать функции OrderOpenPrice(), OrderTakeProfit(), OrderStopLoss() и опционально функции OrderExpiration() при передаче значений в функцию OrderModify(). Наконец, мы будем использовать функцию OrderModify(), чтобы добавить стоп-лосс и тейк-профит.

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

int BuyTicket = OrderSend(Symbol(),OP_BUY,LotSize,Ask,UseSlippage,0,0, "Ордер на покупку",MagicNumber,0,Green);
 
    if(BuyTicket > 0)
      {
        OrderSelect(BuyTicket,SELECT_BY_TICKET);
        double OpenPrice = OrderOpenPrice();
        if(StopLoss > 0) double BuyStopLoss = OpenPrice – (StopLoss * UsePoint);
        if(TakeProfit > 0) double BuyTakeProfit = OpenPrice + (TakeProfit * UsePoint);
 
        if(BuyStopLoss > 0 || BuyTakeProfit > 0)
          {
             bool TicketMod = OrderModify(BuyTicket,OrderOpenPrice(),BuyStopLoss,
               BuyTakeProfit,0);
} }

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

Мы используем оператор if, чтобы убедиться, что тикет BuyTicket действителен, то есть больше нуля. Если это так, мы вызываем функцию OrderSelect(), используя тикет BuyTicket. Мы получаем цену открытия для ордера, используя OrderOpenPrice(), и назначаем ее переменной OpenPrice.

Далее мы рассчитываем стоп-лосс и тейк-профит относительно цены открытия ордера, который мы только что разместили. Сначала мы проверяем, являются ли внешние переменные StopLoss и TakeProfit больше нуля. Если это так, мы рассчитываем новые цены для стоп-лосса и тейк-профита.

Наконец, мы вызываем функцию OrderModify(), чтобы добавить наш стоп-лосс и зафиксировать прибыль в ордере. Сначала мы проверяем, чтобы переменные BuyStopLoss или BuyTakeProfit отличались от нуля. Если мы попытаемся изменить порядок с неизменными значениями, мы получим код ошибки 1 из функции OrderModify().

Первым параметром для OrderModify() является наш номер BuyTicket. Мы также можем использовать OrderTicket(). Второй параметр — цена нового ордера. Поскольку мы не изменяем цену ордера, мы используем функцию OrderOpenPrice(), чтобы указать, что цена ордера не изменилась.

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

Переменные BuyStopLoss и BuyTakeProfit передают измененный стоп-лосс и значения тейк-профита в функцию OrderModify(). Если вы планируете использовать время истечения ордера для отложенных ордеров, вы можете использовать OrderExpiration(). В противном случае просто используйте 0.

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

Как изменять отложенные ордера?

Функция OrderModify() также можно использовать для изменения цены отложенного ордера. Если цена отложенного ордера уже была достигнута и ордер был исполнен, он больше не является отложенным ордером и его цена открытия не может быть изменена.

Мы будем использовать переменную NewPendingPrice для представления новой цены ордера.

    OrderSelect(Ticket,SELECT_BY_TICKET);
    if(NewPendingPrice != OrderOpenPrice())
      {
bool TicketMod = OrderModify(Ticket,NewPendingPrice,OrderStopLoss(), OrderTakeProfit(),0);
}

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

Для OrderModify() мы указываем наш тикет ордера, новую цену ордера, сохраненную в NewPendingPrice, и неизменные значения стоп-лосс и тейк-профит, представленные OrderStopLoss() и OrderTakeProfit(). Мы не используем время истечения для этого ордера, поэтому мы подставляем 0 в качестве параметра истечения срока действия.

Как разместить стоп-лосс и тейк-профит для каждого открытого ордера?

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

// Допустимое проскальзывание.
extern double Slippage=3;  //Allowed Slippage
 
extern int TakeProfit=40;  //Размер тейк-профита в пунктах.
extern int StopLoss=20;    //Размер стоп-лосса в пунктах.
 
//В соответствии с рекомендациями нам необходимо нормализовать цену, чтобы правильно рассчитать тейк-профит и стоп-лосс.
double CalculateNormalizedDigits()
{
   if(Digits<=3) {
   return(0.01);
   } 
   else if(Digits>=4) {
      return(0.0001);
   }
   else return(0);
}
 
//Функцию UpdateOpenOrders возвращает количество ордеров, которые должны быть изменены.
int UpdateOpenOrders(){
 
   int TotalUpdated=0;  //Мы хотим посчитать, сколько ордеров было изменено.
 
   double nDigits=CalculateNormalizedDigits();
 
   //Нормализируем проскальзывание.
   if(Digits==3 || Digits==5){
      Slippage=Slippage*10;
   }
 
   //Перебираем все ордера в обратном порядке.
   for(int i=OrdersTotal()-1; i>=0; i--) {
 
      //Мы выбираем ордера по индексу. Если выбор прошел успешно, мы приступаем к их изменению.
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)){
         // Проверяем, относится ли ордер к той же валютной паре на графике, на котором выполняется скрипт.
         if(OrderSymbol()==Symbol()){
            double OpenPrice, StopLossPrice, TakeProfitPrice;
            // Получаем цену открытия.
            OpenPrice=OrderOpenPrice();
            // Мы рассчитываем стоп-лосс и тейк-профит в зависимости от типа ордера.
            if(OrderType()==OP_BUY){
               StopLossPrice=NormalizeDouble(OpenPrice-StopLoss*nDigits,Digits);
               TakeProfitPrice=NormalizeDouble(OpenPrice+TakeProfit*nDigits,Digits);
            }
            if(OrderType()==OP_SELL){
               StopLossPrice=NormalizeDouble(OpenPrice+StopLoss*nDigits,Digits);
               TakeProfitPrice=NormalizeDouble(OpenPrice-TakeProfit*nDigits,Digits);
            }         
            if(OrderModify(OrderTicket(),OpenPrice,StopLossPrice,TakeProfitPrice,CLR_NONE)){
               TotalUpdated++;
            }
            else{
               Print("Не удалось обновить заказ с ошибкой - ",GetLastError());
            }
 
         }
 
         // Если ордер изменяется корректно, мы увеличиваем счетчик измененных ордеров. Если ордер не изменяется, мы выводим ошибку.
     }
      else{
         Print("Не удалось изменить ордер - ",GetLastError());
      }  
 
      // Устанавливаем небольшую паузу.
      Sleep(300);
   }
   //Если цикл завершается, это означает, что для данного инструмента больше нет открытых ордеров.
   return(TotalUpdated);
}
 
 
void OnStart()
{
   Print("Сколько ордеров было изменено? ",UpdateOpenOrders());
}

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

 
#property copyright     "Александр Паркер"
#property link          "https://traderblog.net/"
#property version       "1.00"
#property strict
 
#property show_inputs
 
//Внешние переменные
extern int TakeProfit=40;              //Размер тейк-профита в пунктах.
extern int StopLoss=20;                //Размер стоп-лосса в пунктах.
extern bool OnlyMagicNumber=false;     //Изменять только ордера с magic number.
extern int MagicNumber=0;              //Magic number.
extern bool OnlyWithComment=false;     //Изменять ордера с определенным комментарием.
extern string MatchingComment="";      //Комментарий.
extern double Slippage=2;              //Проскальзывание.
extern int Delay=0;                    //Задержка между модификацией ордеров.
 
//Нормализуем значение цены для рассчета стоп-лосса и тейк-профита.
double CalculateNormalizedDigits()
{
   if(Digits<=3){
      return(0.01);
   }
   else if(Digits>=4){
      return(0.0001);
   }
   else return(0);
}
 
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   //Счетчик ордеров
   int TotalModified=0;
 
   //Нормализуем проскальзывание.
   if(Digits==3 || Digits==5){
      Slippage=Slippage*10;
   }
   double nDigits=CalculateNormalizedDigits();
 
   //Перебираем ордера.
   for(int i=OrdersTotal()-1; i>=0; i--){
 
      //Выбераем ордер. Если орден не выбран, выводим ошибку и переходим к следующему индексу.
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) == false) {
         Print("Ошибка. Нельзя выбрать ордер - ",GetLastError());
         continue;
      } 
 
      //Проверяем, совпадает ли ордер в соответствии с заданными критериями. Если критерии не совпадают, переходим к следующим.
      if(OrderSymbol()!=Symbol()) continue;
      if(OnlyMagicNumber && OrderMagicNumber()!=MagicNumber) continue;
      if(OnlyWithComment && StringCompare(OrderComment(),MatchingComment)!=0) continue;
 
      //Цены.
      double TakeProfitPrice=0;
      double StopLossPrice=0;
      double OpenPrice=OrderOpenPrice();
      RefreshRates();
      if(OrderType()==OP_BUY){
         TakeProfitPrice=NormalizeDouble(OpenPrice+TakeProfit*nDigits,Digits);
         StopLossPrice=NormalizeDouble(OpenPrice-StopLoss*nDigits,Digits);
      } 
      if(OrderType()==OP_SELL){
         TakeProfitPrice=NormalizeDouble(OpenPrice-TakeProfit*nDigits,Digits);
         StopLossPrice=NormalizeDouble(OpenPrice+StopLoss*nDigits,Digits);      
      }
 
      //Модифицируем ордер.
      if(OrderModify(OrderTicket(),OpenPrice,StopLossPrice,TakeProfitPrice,0,clrNONE)){
         TotalModified++;
      }
      else{
         Print("Ошибка - ",GetLastError());
      }      
 
      //Задержка.
      Sleep(Delay);
 
   }
 
   //Выводим количество модифицированных ордеров.
   Print("Всего ордеров изменено = ",TotalModified);
 
  }
//+------------------------------------------------------------------+

  • #6 901

Доброго дня!Можно к этому индюку приделать ID,чтобы ставить несколько штук на график с разными ТФ?

  • fs_hor_lvl.mq4

    11,9 КБ · Просмотры: 42

  • MetaTrader - EXNESS.png

    MetaTrader — EXNESS.png

    53 КБ · Просмотры: 212

  • #6 902

GUYS PLEASE HELP REMOVE THE ALERT IN THIS BRILLIANT ARROW INDICATOR . PROGRAMMERS I COUNT ON YOU PLEASE

  • 20200804_112748.jpg

    20200804_112748.jpg

    3,4 МБ · Просмотры: 171

  • 20200804_112723.jpg

    20200804_112723.jpg

    3,9 МБ · Просмотры: 178

  • DR ARROW.ex4

    7,3 КБ · Просмотры: 74

  • #6 903

Заведите старый индюк 15 года.

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

  • #6 904

GUYS PLEASE HELP REMOVE THE ALERT IN THIS BRILLIANT ARROW INDICATOR . PROGRAMMERS I COUNT ON YOU PLEASE

for this purpose it is necessary a format mq4

  • #6 905

Постоянно возникает ошибка OrderModify error 1, хотя вроде бы тут «if(OrderStopLoss()<(DONlow+minstoplevel*pp))» у меня есть проверка на минимальный стоп
Помогите люди добрые, советник и индюк приладываю

double DONhigh, DONlow;(данные с индикатора)

extern bool   AllPositions  =True;         // Управлять всеми позициями
extern bool   ProfitTrailing=False;          // Тралить только профит
extern double    TrailingStep  =5;             // Шаг трала
extern double    TrailingStop  =2;


//+------------------------------------------------------------------+
//| Сопровождение позиции простым тралом                             |
//+------------------------------------------------------------------+
void TrailingPositions()
  {
   double pBid, pAsk, pp;
   double minstoplevel=MarketInfo(Symbol(),MODE_STOPLEVEL);
//----
   pp=MarketInfo(OrderSymbol(), MODE_POINT);
   if(OrderType()==OP_BUY)
     {
      pBid=MarketInfo(OrderSymbol(), MODE_BID);
      if(!ProfitTrailing || (pBid-OrderOpenPrice())>TrailingStop*pp)
        {
         //if(OrderStopLoss()<pBid-(minstoplevel+TrailingStop+TrailingStep-1)*pp)
         if(OrderStopLoss()<(DONlow+minstoplevel*pp))
           {
            ModifyStopLoss(DONlow);
            return;
           }
        }
     }
   if(OrderType()==OP_SELL)
     {
      pAsk=MarketInfo(OrderSymbol(), MODE_ASK);
      if(!ProfitTrailing || OrderOpenPrice()-pAsk>TrailingStop*pp)
        {
         //if(OrderStopLoss()>pAsk+(minstoplevel+TrailingStop+TrailingStep-1)*pp || OrderStopLoss()==0)
         if(OrderStopLoss()>(DONhigh+minstoplevel*pp))
           {
            ModifyStopLoss(DONhigh);
            return;
           }
        }
     }
  }
//+------------------------------------------------------------------+
//| Перенос уровня StopLoss                                          |
//| Параметры:                                                       |
//|   ldStopLoss - уровень StopLoss                                  |
//+------------------------------------------------------------------+
void ModifyStopLoss(double ldStopLoss)
  {
   bool fm;
   fm=OrderModify(OrderTicket(),OrderOpenPrice(),NormalizeDouble(ldStopLoss,Digits),OrderTakeProfit(),0,CLR_NONE);
  }

  • 7.mq4

    28,7 КБ · Просмотры: 26

  • Doncian.mq4

    3,4 КБ · Просмотры: 22

  • #6 906

Постоянно возникает ошибка OrderModify error 1, хотя вроде бы тут «if(OrderStopLoss()<(DONlow+minstoplevel*pp))» у меня есть проверка на минимальный стоп
Помогите люди добрые, советник и индюк приладываю

ERR_NO_RESULT — OrderModify пытается изменить уже установленные значения такими же значениями. Необходимо изменить одно или несколько значений и повторить попытку…
говоря простыми словами, при модификации происходит попытка уровень стоплосса (тейкпрофита) поменять на точно такое же значение

  • #6 907

Можно исправить робота? Многовалютник. Автор заявил, что установлено ограничение работы до 30 августа 2020 года. Исправить ограничение или продлить лет на «…цать» работу робота.

Ставил на демо на месяц, плечо 1:300. Депозит 20$. Робот показал прекрасную устойчивость. Автор рекомендовал депозит от 100$, тем не менее на 20$ просадка не была более 6% за счет оригинального алгоритма работы.

  • SmoothieH.ex4

    168 КБ · Просмотры: 82

  • 111.jpg

    111.jpg

    98 КБ · Просмотры: 118

gek

Элитный участник


  • #6 908

Можно исправить робота? Многовалютник. Автор заявил, что установлено ограничение работы до 30 августа 2020 года. Исправить ограничение или продлить лет на «…цать» работу робота.

Ставил на демо на месяц, плечо 1:300. Депозит 20$. Робот показал прекрасную устойчивость. Автор рекомендовал депозит от 100$, тем не менее на 20$ просадка не была более 6% за счет оригинального алгоритма работы.

Привет!
Как работал с ним?
Тайм,пары,брокер,преффиксы и т.д.
Хотел бы поставить,глянуть что за зверь.

  • #6 909

Привет!
Как работал с ним?
Тайм,пары,брокер,преффиксы и т.д.
Хотел бы поставить,глянуть что за зверь.

У меня стоит на Робофорекс на демо. Все по дефолту. Поставил на пару евро-доллар, таймфрейм H1. В настройки не лазил, так как интересовала не сама торговля, а именно проверка устойчивости робота. Далее кидаешь робота на график, появляется мультивалютное меню. Нажимаешь кнопу new order, она становится ярко-синей, всё торговля началась. Робот входит в рынок только по ему известному алгоритму, ведет только 1 с валютную пару до ее закрытия. У меня было максимум 3 ордера в сетке. Хеджирования не видел, хотя автор заявляет, что оно возможно. Не мартинил, ордера имели одинаковую лотность. Количество ордеров в день по разному. Бывает 2-3, а бывает с десяток. Торгует нечасто. Я много перепробовал мультивалютников, лучше этого не видел. Робот по всей видимости был выложен в паблик на soehoe.id, там есть тема от автора.

  • robot.jpg

    robot.jpg

    146,2 КБ · Просмотры: 96

Последнее редактирование: 06.08.2020

  • #6 910

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

Привет!
Спасибо за ответ! Ответ нашёл за бугром.
Это работает, вам сначала нужно нарисовать вилы Эндрю, затем переименовать их в соответствии с индикатором (по умолчанию это AL1), затем добавить несколько тиков, и вы получите это. 1596776667679.png

  • #6 911

[QUOTE = «Vaporesso, post: 1564801, member: 170338»]
Is it possible to fix it?
[/ QUOTE]
adjusted

  • RSI-8_CROSS-55 45_ARROW.ex4

    11,8 КБ · Просмотры: 19

  • RSI-8_CROSS-55 45_ARROW.mq4

    6,7 КБ · Просмотры: 23

  • #6 912

Нда…Я тогда дальше не буду ковырять — обновленный вариант сами попробуете. Если что-то нужно дальше с ним делать — это уже отдельная тема..

  • AML_v21.mq4

    29,1 КБ · Просмотры: 60

  • #6 913

Добрый день! Не кодил около года. Прошу помочь. Прописал в коде советника:
if (Bid==TP)
{
SendNotification(Symdol()+» закрой ордер»);
TP=0;
}
Уведомление не приходит… может функцию уведомления еще и в while прописать?

  • #6 914

Прописал в коде советника:
if (Bid==TP)
{
SendNotification(Symdol()+» закрой ордер»);

Привет. Ну, для начала исправьте Symdol() на Symbol() :)
и в самом терминале есть настройки на отправку пуш уведомлений?

  • #6 915

Привет. Ну, для начала исправьте Symdol() на Symbol() :)
и в самом терминале есть настройки на отправку пуш уведомлений?

Сори за ошибку) код сюда не копировал, а от руки писал) Терминал настроен, уведомления приходят с сигналом на открытие позиции, а при достижении определенной цены, уведомления не приходят… но иногда случается чудо и уведомление приходит. Вот и думаю может еще в while функцию записать с условием false

  • #6 916

Добрый день! Не кодил около года. Прошу помочь. Прописал в коде советника:
if (Bid==TP)
{
SendNotification(Symdol()+» закрой ордер»);
TP=0;
}
Уведомление не приходит… может функцию уведомления еще и в while прописать?

ну, сравнение 2 чисел double это тема для небольшого, но крайне поучительного разговора…
однако, сейчас не об этом… если ты думаешь, что условие Bid==TP — встречается часто, то тут форменное заблуждение… на 5-знаке цена 2 часа будет скакать около ТР и ни разу это условие не сработает…
пропиши Bid>=TP — и по смыслу вернее будет, и сработает надежнее)

  • #6 917

Вот и думаю может еще в while функцию записать с условием false

Функция while промежуточная (универсальная) и как вы ее и в каком месте используете я понятия не имею — я же не видел код.
if (Bid==TP) — такой вариант очень редкий на совпадение — идеальное совпадение текущего бида с каким-то рассчитанным ТП поймать очень сложно. Нужно проверки делать типа >= для бай или <= для селл, и то в зависимости от момента, когда это должно сработать.

  • #6 918

vladradon, AlexeNP спасибо вам за совет. Просто хотел как раз таки поймать условие Bid==TP т.к. условие писал и для бай и для селл, думал будет работать). Сегодня буду переписывать через <= >=. Еще раз спасибо за оперативную помощь!)

  • #6 919

Хочу ребята, умельцы наши попросить моленько исправить индикатор IRES он не мой говорю сразу и в открытом коде его не найдёте есть только в ex, нужно просто удалить уровня НКЗ с этого индикатора, а то вылазят даже при отключенных настройках. Писал хозяевам индюка а в ответ тишина а эти уровня мне мешают. Помогите пожалуйста.

  • IRES.ex4

    2,2 МБ · Просмотры: 51

  • #6 920

Хочу ребята, умельцы наши попросить моленько исправить индикатор IRES он не мой говорю сразу и в открытом коде его не найдёте есть только в ex, нужно просто удалить уровня НКЗ с этого индикатора, а то вылазят даже при отключенных настройках. Писал хозяевам индюка а в ответ тишина а эти уровня мне мешают. Помогите пожалуйста.

без исходника такие вещи не сделать.

Я пытаюсь изменить Заказ, но всегда получаю Error #1 .

Из своего исследования я обнаружил, что ошибка 1 означает, что у меня неправильный входной параметр. Как я могу исправить мою функцию OrderModify() ?

    stoploss = NormalizeDouble(Ask - Point * TrailingStop,Digits);
    int ticket;
    takeprofit = NormalizeDouble(Ask + Point * TrailingStopTP,Digits);
    double minstoplevel = MarketInfo( Symbol(), MODE_STOPLEVEL );
    if(stoploss > NormalizeDouble(Ask - Point*minstoplevel,Digits)) {
        stoploss = NormalizeDouble(Ask - Point*minstoplevel,Digits);
    }
    if(takeprofit < NormalizeDouble( Ask + Point*minstoplevel2, Digits )) {
        takeprofit = NormalizeDouble( Ask + Point*minstoplevel2, Digits );
    }
    if(AccountFreeMarginCheck(Symbol(),OP_SELL,lotsize)>0) {
        ticket=OrderSend(Symbol(),OP_BUY,lotsize,Ask, 0, 0.0, 0.0, "comment", MagicNumber, 0, Lime);
        if(ticket<0) {
            Print("Order send failed with error #",GetLastError());       
        } else {
            Print("Order send sucesso!! Ticket#", ticket);
            res=OrderModify(ticket,OrderOpenPrice(),stoploss,takeprofit,0,Blue);
            if(res==false) {
                Print("Error modifying order!, error#",GetLastError());
            } else {
                Print("Order modified successfully, res#", res);
            }            
        }
    } else {
        Print("Sem dinheiro na conta D=");
    }
 }

2 ответа

Лучший ответ

Не совсем « неправильно «, OrderModify() юридически устанавливает _LastError == 1

Это может вызвать небольшое удивление, но OrderModify() обязан сигнализировать _LastError == 1 в случае, если вызов был синтаксически и семантически правильным, однако , значения, предоставленные для модификации (й), на самом деле были такими же, поскольку идентифицированный ticket# уже был в базе данных.

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

Можно предварительно проверить все поля на предмет потенциальной идентичности, что может позволить нашему коду пропустить вызов OrderModify() именно в этом случае идентичности- {current | target} значения.

ERR_NO_RESULT == 1               // No error returned, but the result is unknown

GetLastError() — возвращает последний сгенерированный код ошибки. То же значение доступно через системную переменную с именем _LastError . Это значение можно сбросить до нуля перед критическим действием, вызвав ResetLastError() .

Коды ошибок определены в stderror.mqh .

Чтобы распечатать описание ошибки, вы можете использовать функцию ErrorDescription() , определенную в файле stdlib.mqh .

#include <stderror.mqh>
#include <stdlib.mqh>


4

user3666197
5 Окт 2015 в 11:41

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

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

double entryPrice = NormalizeDouble( entryPrice, Digits );
double stoploss   = NormalizeDouble( stoploss,   Digits );
double target     = NormalizeDouble( target,     Digits );

Затем передайте их в вызов OrderModify().


1

user3666197
18 Янв 2017 в 07:57

Что значит 2010.02.01 17:00 MyExpert GBPUSD,M15: OrderModify error 130
почему обычно эта ошибка возникает?

Очень много подобных вопросов мне приходит. Поэтому публикую таблицу кодов ошибок. Например посмотрев вышеописанную ошибку error 130 становится понятно, что функция OrderModify пытается изменить стоп-лосс или тейк-профит слишком близко к текущей цене.

Коды ошибок

GetLastError() — функция, возвращающая коды ошибок. Кодовые константы ошибок определены в файле stderror.mqh. Для вывода текстовых сообщений следует использовать функцию ErrorDescription(), определенную в файле stdlib.mqh.

Коды ошибок, возвращаемые торговым сервером или клиентским терминалом:

Значение Описание
0 Нет ошибки
1 Нет ошибки, но результат неизвестен
2 Общая ошибка
3 Неправильные параметры
4 Торговый сервер занят
5 Старая версия клиентского терминала
6 Нет связи с торговым сервером
7 Недостаточно прав
8 Слишком частые запросы
9 Недопустимая операция нарушающая функционирование сервера
64 Счет заблокирован
65 Неправильный номер счета
128 Истек срок ожидания совершения сделки
129 Неправильная цена
130 Неправильные стопы
131 Неправильный объем
132 Рынок закрыт
133 Торговля запрещена
134 Недостаточно денег для совершения операции
135 Цена изменилась
136 Нет цен
137 Брокер занят
138 Новые цены
139 Ордер заблокирован и уже обрабатывается
140 Разрешена только покупка
141 Слишком много запросов
145 Модификация запрещена, так как ордер слишком близок к рынку
146 Подсистема торговли занята
147 Использование даты истечения ордера запрещено брокером
148 Количество открытых и отложенных ордеров достигло предела, установленного брокером.

Коды ошибок выполнения MQL4 программы:

Значение Описание
4000 Нет ошибки
4001 Неправильный указатель функции
4002 Индекс массива — вне диапазона
4003 Нет памяти для стека функций
4004 Переполнение стека после рекурсивного вызова
4005 На стеке нет памяти для передачи параметров
4006 Нет памяти для строкового параметра
4007 Нет памяти для временной строки
4008 Неинициализированная строка
4009 Неинициализированная строка в массиве
4010 Нет памяти для строкового массива
4011 Слишком длинная строка
4012 Остаток от деления на ноль
4013 Деление на ноль
4014 Неизвестная команда
4015 Неправильный переход
4016 Неинициализированный массив
4017 Вызовы DLL не разрешены
4018 Невозможно загрузить библиотеку
4019 Невозможно вызвать функцию
4020 Вызовы внешних библиотечных функций не разрешены
4021 Недостаточно памяти для строки, возвращаемой из функции
4022 Система занята
4050 Неправильное количество параметров функции
4051 Недопустимое значение параметра функции
4052 Внутренняя ошибка строковой функции
4053 Ошибка массива
4054 Неправильное использование массива-таймсерии
4055 Ошибка пользовательского индикатора
4056 Массивы несовместимы
4057 Ошибка обработки глобальныех переменных
4058 Глобальная переменная не обнаружена
4059 Функция не разрешена в тестовом режиме
4060 Функция не подтверждена
4061 Ошибка отправки почты
4062 Ожидается параметр типа string
4063 Ожидается параметр типа integer
4064 Ожидается параметр типа double
4065 В качестве параметра ожидается массив
4066 Запрошенные исторические данные в состоянии обновления
4067 Ошибка при выполнении торговой операции
4099 Конец файла
4100 Ошибка при работе с файлом
4101 Неправильное имя файла
4102 Слишком много открытых файлов
4103 Невозможно открыть файл
4104 Несовместимый режим доступа к файлу
4105 Ни один ордер не выбран
4106 Неизвестный символ
4107 Неправильный параметр цены для торговой функции
4108 Неверный номер тикета
4109 Торговля не разрешена
4110 Длинные позиции не разрешены
4111 Короткие позиции не разрешены
4200 Объект уже существует
4201 Запрошено неизвестное свойство объекта
4202 Объект не существует
4203 Неизвестный тип объекта
4204 Нет имени объекта
4205 Ошибка координат объекта
4206 Не найдено указанное подокно
4207 Ошибка при работе с объектом

Если Вы хотите изучать язык MQL или вам понравилась данная публикация — Вы можете подписаться на получение новых материалов сайта mql4you.ru по

RSS

или по e-mail:

Другие публикации рубрики «FAQ по MQL и Metatrader»:

  • Вопрос №9 «Как заставить работать советник при выключенном компьютере?»
  • Вопрос №8 «Как рассчитать размер лота в зависимости от размера стоплосса?»
  • Можно ли настроить нестандартный тайм-фрейм в MT4? — Вопрос №7
  • Вопрос №6 «Как уменьшить размер папки с терминалом MT4?»
  • Вопрос №4 — «Выключение компьютера из MQL»
  • Вопрос №3
  • Вопрос №2
  • Вопрос №1
  • В рубриках: FAQ по MQL и Metatrader
  • Понравилась статья? Поделить с друзьями:

    Читайте также:

  • Ordercloseby error 3
  • Orderclose error 4051
  • Orderclose error 138 mql4
  • Orderclose error 131 mql4
  • Order would immediately trigger ошибка

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии