Отправлено: 14.04.14 09:56. Заголовок: Я в шоке! Подскажите.
Всем привет! Я в шоке! Выпал из рынка на 3,5 месяца, а тут такие перемены. Игорь подскажи, где можно ознакомиться с изменениями в MQL4? Хотел перенести все данные на новый комп, но некоторые индикаторы после компиляции перестают работать. Вот один из них. http://gfile.ru/a8cCP Хотя не перекомпилированные файлы работают. Компиляция ошибок в коде не выявляет. Но при отладке выдается ошибка формирования массива стр.67. Но в чем ошибка не пойму. Буду благодарен, если найдешь время исправить.
Сообщение: 494
Зарегистрирован: 04.03.13
Откуда: Москва
Репутация:
1
Отправлено: 14.04.14 10:41. Заголовок: Sergey пишет: Всем ..
Sergey пишет:
цитата:
Всем привет! Я в шоке! Выпал из рынка на 3,5 месяца, а тут такие перемены.
Привет, Сергей! С возвращением !
У Игоря была статья про возможности обновленного MQL, но видимо надо его попросить обновить две базовые статьи: "Как создать советник, не обладая навыками программирования", "Как создать индикатор, не обладая навыками программирования", и шаблоны к ним.
Сообщение: 508
Зарегистрирован: 04.03.13
Откуда: Москва
Репутация:
1
Отправлено: 17.04.14 05:41. Заголовок: Sergey пишет: Всем ..
Sergey пишет:
цитата:
Всем привет! Я в шоке! Выпал из рынка на 3,5 месяца, а тут такие перемены. Игорь подскажи, где можно ознакомиться с изменениями в MQL4? Хотел перенести все данные на новый комп, но некоторые индикаторы после компиляции перестают работать. ... Хотя не перекомпилированные файлы работают. Компиляция ошибок в коде не выявляет. Но при отладке выдается ошибка формирования массива стр.67. Но в чем ошибка не пойму. Буду благодарен, если найдешь время исправить.
Статья на MQL4 по теме. В статье рассмотрены возможные ошибки, возникающие при компиляции старых программ и методы их устранения. Может что пригодится.
1.Ошибки компиляции ◾1.1. Идентификатор совпадает с зарезервированным словом ◾1.2. Специальные символы в наименованиях переменных и функций ◾1.3. Ошибки использования оператора switch ◾1.4. Возвращаемые значения у функций
◾1.5. Массивы в аргументах функций
2.Ошибки времени выполнения ◾2.1. Выход за пределы массива (Array out of range) ◾2.2. Деление на ноль (Zero divide) ◾2.3. Использование 0 вместо NULL для текущего символа ◾2.4. Строки в формате Unicodе и их использование в DLL ◾2.5. Совместное использование файлов ◾2.6. Особенность преобразования datetime
3.Предупреждения компилятора ◾3.1. Пересечения имен глобальных и локальных переменных ◾3.2. Несоответствие типов ◾3.3. Неиспользуемые переменные
Ошибки: 1. Выход за пределы массивов при расчете начального бара (переменная limit). В момент начала работы индикатора выражение
цитата:
limit = Bars - counted_bars;
указывает на бар с индексом Bars, которого не существует. Bars - это общее количество баров на графике, которое индексируется с нуля. Поэтому последний бар графика будет иметь индекс Bars - 1. Чтобы подобное не происходило, нужно начинать обработку баров с того бара, для которого будет произведен корректный расчет всех значений индиктаора. В общем случае можно поступить так:
Но в данном случае это тоже неправильно, т. к. необходимо обеспечить расчет средней скользящей с периодом Periods. То есть от конца графика нужно отодвинуться еще на Periods баров:
цитата:
limit = (int)MathMin(Bars - counted_bars, Bars - Periods - 1);
2. Связывание индикаторных буферов с индексами произведено неправильно:
В новом MQL4 логические выражения обрабатываются по укороченному сценарию. Это означает, что если после вычисления первой части выражения результат всего выражения уже не изменится, то вторая и последующая части не вычисляются. В данном случае при успешном связывании первого буфера становится ясно, что выражение будет иметь результат false. Потому последующие буфера не связываются. Правильно делать так:
В этом случае результат будет true как только появится первая ошибка связывания. Связывание остальных буферов уже не потребуется, т. к. индикатор и так не должен работать.
Игорь, огромное спасибо! Как всегда исчерпывающий ответ.... Выход за пределы массивов при расчете начального бара я исправил, согласно новым функциям и правилам расчета индикаторов. И все равно не мог понять, почему индикатор не отображается. Оказалось проблема не только в этом. Разбор ошибок самый эффективный способ обучения... Очень благодарен за такую ветку.
Отправлено: 14.08.14 09:46. Заголовок: В папке Includ файл ..
В папке Include файл MovingAverages.mqh Функция double ExponentialMA(const int position,const int period,const double prev_value,const double &price[])
Отправлено: 15.08.14 16:32. Заголовок: Sergey пишет: Что о..
Sergey пишет:
цитата:
Что обозначает параметр prev_value?
Это предыдущее значение экспоненциального среднего. Расчет значения текущего экспоненциального среднего производится на основе предыдущего значения. Подразумевается, что отсутствие предыдущего значения допускается только для самого первого расчета в истории. Для всех последующих значений предыдущие значения уже будут.
Sergey пишет:
цитата:
И каково предназначение символа & ( &price[])?
В MQL4/5 символ "&", поставленный в объявлении переменной перед ее именем, означает ссылку на переменную. Ссылка в большинстве случаев дает возможность изменять значение переменной внутри локальной функции так, что измененное значение будет доступно после окончания выполнения этой локальной функции. Вот простой пример. В одной функции объявляются переменные a и b, но их значения меняются в другой функции, в которой они не объявлены, а переданы по ссылке:
цитата:
void SwapVars(int &a, int &b) { int c = a; a = b; b = c; } void OnTick() { int a = 5; int b = 10; Print("До изменения: a = ", a, ", b = ", b);
SwapVars(a, b); Print("После изменения: a = ", a, ", b = ", b); }
В случае с функцией ExponentialMA ссылка имеет другое назначение. Перед типом данных установлен спецификатор const, который указывает на тот факт, что переменная, передаваемая по ссылке, не может быть изменена. Возникает логичный вопрос - а зачем тогда ссылка? Здесь она нужна по той причине, что в функцию требуется передать не одно значение, а целый массив. Если передавать массив по значению, то чем большее количество элементов в массиве, тем дольше он будет передаваться в функцию. Ссылка же дает возможность не передавать все значения массива, а просто указать место в памяти, где все эти значения лежат. При этом передающая функция "может быть спокойна за целостность данных", т. к. функция ExponentialMA не имеет право изменять данные массива price.
Не могу понять, почему после установки индикатора на нулевом баре не обновляется координата j_volume, хотя текущая гистограмма объема отображается верно.
Отправлено: 16.09.14 12:45. Заголовок: Sergey пишет: Не мо..
Sergey пишет:
цитата:
Не могу понять, почему после установки индикатора на нулевом баре не обновляется координата j_volume, хотя текущая гистограмма объема отображается верно.
Если руководствоваться только приведенным участком кода, то можно говорить только об одной ошибке. Вместо:
цитата:
ObjectDelete("name");
нужно написать:
цитата:
ObjectDelete(name);
Ведь name - это имя переменной, а в коде оно используется как имя объекта. То есть удаляется объект с названием name, а создается потом совершенно другой объект с названием, которое находится в переменной name.
При обновлении данных графических объектов лучше использовать не удаление/создание, а создание/модификацию:
цитата:
string name = PREFIX + ...; if (ObjectFind(name) < 0) // объекта нет - можно создавать { ObjectCreate(..); // назначение свойств объекта } else { // модификация объекта - те свойства, которые нужно изменить }
Scriptong пишет: [quote]` Добрый день уважаемый Игорь! Пожалуйста помогите с кодом?! Надо написать простой советник по этим индикатор(вложил ссылки ниже). Я сам попробовал, но не получилось. Почему то не возможно получить сигнал от буфер индикатора. Есть какой то способ получить сигнал от него?
Условии: BUY когда линия индикатора више "0" и SELL когда линия индикатора ниже "0". Очень прощу от вас, пожалуйста помогите?! Жду ваше ответы.
Снова приветствую! Уважаемый Игорь есть еще просьба. Вложенный в архиве есть индикатор и советник. С кодом нету ни каких проблему, но не работает в новым билдом метатрейдера(компилируется без ошибки). Помогите пожалуйста?! http://qclk.ru/ks/0IUp
Сообщение: 838
Зарегистрирован: 04.03.13
Откуда: Москва
Репутация:
2
Отправлено: 20.09.14 18:57. Заголовок: Husanboy пишет: С к..
Husanboy пишет:
цитата:
С кодом нету ни каких проблему, но не работает в новым билдом метатрейдера(компилируется без ошибки). Помогите пожалуйста?!
В прежней версии этот индикатор состоял из 2- частей - сам индикатор RSH.mq4 в котором был такой вызов второго индикатора HullMA.mq4 rel=(iCustom(NULL,0,"HullMA",periodoMA,tipoPrecio,tipoPromedio,0,k)-iCustom(NULL,0,"HullMA",periodoMA,tipoPrecio,tipoPromedio,0,i+1))+iCustom(NULL,0,"HullMA",periodoMA,tipoPrecio,tipoPromedio,0,i)-iCustom(NULL,0,"HullMA",periodoMA,tipoPrecio,tipoPromedio,0,k+1);
В Вашей версии индикатор HullMA введен в индикатор RSH в виде функции и вызов теперь выглядит так: rel=hma[x]-hma[x+1];
Я взял старую отдельную версию индикатора HullMA и накинул ее на график - она ничего не рисует. Так что проблема в этой части индикатора и функция hma не работает. Если получится найти причину и заставить работать hma, то и RSH начнет выдавать сигналы советнику.
Делаю советник, одна из функций которого, при параметре Symbols=false (не учитывать текущий символ) закрывать все открытые ордера, по всем валютным парам.
FindOrders(); if (CommonProfit>Profit || CommonProfit<-AccountBalance()/100*Loss) { while (true) { CloseAllOrders(); FindOrders(); if (BuyCount==0 && SellCount==0) break; } }
//+-------------------------------------------------------------------------------------+ //| Поиск своих ордеров. | //+-------------------------------------------------------------------------------------+ void FindOrders() { //---- BuyCount = 0; SellCount = 0; CommonProfit = 0; //---- for (int i = 0; i < OrdersTotal(); i++) // Используется весь список ордеров if (OrderSelect(i, SELECT_BY_POS)) // Убедимся, что ордер выбран if ((OrderMagicNumber() == MagicNumber || MagicNumber<0) // Ордер соответствует настройкам MagicNumber && (OrderSymbol() == Symbol() || !Symbols)) // Ордер соответствует настройкам валютной паре { CommonProfit += OrderProfit()+OrderSwap(); // Подсчет совокупного профита if (OrderType() == OP_SELL) SellCount++; if (OrderType() == OP_BUY) BuyCount++; } } //=======================================================================================
//+-------------------------------------------------------------------------------------+ //| Закрытие позиций | //+-------------------------------------------------------------------------------------+ void CloseAllOrders() { for (int i = 0; i < OrdersTotal(); i++) // Используется весь список ордеров if (OrderSelect(i, SELECT_BY_POS)) // Убедимся, что ордер выбран if ((OrderMagicNumber() == MagicNumber || MagicNumber<0) // Ордер соответствует настройкам MagicNumber && (OrderSymbol() == Symbol() || !Symbols)) // Ордер соответствует настройкам валютной пары
if (WaitForTradeContext()) { if (OrderType()==OP_BUY) if(OrderClose(OrderTicket(), OrderLots(), NT(Bid), Slippeg)) continue; if (OrderType()==OP_SELL) if(OrderClose(OrderTicket(), OrderLots(), NT(Ask), Slippeg)) continue; } } //=======================================================================================
Однако, как только параметр устанавливается Symbols=false, советник виснет, когда поступает команда на закрытие позиций, хотя с текущим символом (при Symbols=true) проблем таких нет. В чем причина,понять не могу.
Отправлено: 11.11.14 14:24. Заголовок: Sergey пишет: В чем..
Sergey пишет:
цитата:
В чем причина,понять не могу.
Такой код не сможет закрыть рыночные ордера, открытые по символам, отличным от текущего, т. к. цена закрытия указывается в ценах текущего символа. Для мультивалютных программ следует использовать такую конструкцию закрытия:
if (OrderClose(OrderTicket(), OrderLots(), closePrice, Slippeg)) continue;
Думаю, во время зависаний в журнале эксперта было огромное количество ошибок - неправильные цены.
Также при закрытии ордеров необходимо использовать обратный цикл перебора, а то будете закрывать ордера через один. Ну и не лучшее решение делать бесконечные циклы (while(true)). Как минимум, нужно использовать !IsStopped().
Такой код не сможет закрыть рыночные ордера, открытые по символам, отличным от текущего, т. к. цена закрытия указывается в ценах текущего символа. Для мультивалютных программ следует использовать такую конструкцию закрытия:
Отправлено: 13.11.14 16:58. Заголовок: Индикатор виснет на ..
При компиляции выпадает предупреждение old_color и old_startTime (possible loss of data due to type conversion) Как правильно вывести данные по объекту?
double old_y1=ObjectGet(ObjName, OBJPROP_PRICE1); double old_y2=ObjectGet(ObjName, OBJPROP_PRICE2); color old_color=ObjectGet(ObjName, OBJPROP_COLOR); datetime old_startTime=ObjectGet(ObjName, OBJPROP_TIME1); Аналогично для int A=round(B); Как преобразовать данные? В учебнике ничего нет, или не могу найти где смотреть.
Отправлено: 16.11.14 08:49. Заголовок: Возможно мой вопрос ..
Возможно мой вопрос был не замечен, а потому просто повторюсь.
Sergey пишет:
цитата:
В режиме # property strict При компиляции выпадает предупреждение old_color и old_startTime (possible loss of data due to type conversion) Как правильно теперь вывести данные по объекту?
Возможно мой вопрос был не замечен, а потому просто повторюсь.
Да, действительно, не заметил. Прошу прощения.
Sergey пишет:
цитата:
При компиляции выпадает предупреждение old_color и old_startTime (possible loss of data due to type conversion) Как правильно вывести данные по объекту?
double old_y1=ObjectGet(ObjName, OBJPROP_PRICE1); double old_y2=ObjectGet(ObjName, OBJPROP_PRICE2); color old_color=ObjectGet(ObjName, OBJPROP_COLOR); datetime old_startTime=ObjectGet(ObjName, OBJPROP_TIME1); Аналогично для int A=round(B); Как преобразовать данные? В учебнике ничего нет, или не могу найти где смотреть.
В учебнике этого и не может быть, т. к. учебник был написан для "старого" MQL4, а для нового языка разработчики выпускать учебник не планируют.
Суть проблемы заключается в том, что функция ObjectGet возвращает значение типа double, которое в коде присваивается типам color и datetime соответственно. Таким образом, имеем неявное приведение типов данных с возможной потерей точности значения. Именно об этом напоминает компилятор, заботясь о том, чтобы программа оперировала валидными данными. Для решения вопроса есть два пути:
1. Использовать явное приведение типов, указав компилятору о том, что мы осознаем риск приведения типов и считаем, что в данном случае оно никак не скажется на работоспособности программы. Явное приведение типов выглядит так:
цитата:
color old_color=(color)ObjectGet(ObjName, OBJPROP_COLOR); datetime old_startTime=(datetime)ObjectGet(ObjName, OBJPROP_TIME1); int A = (int)round(B);
2. Использовать специальные функции нового MQL4. Правда, для переменных типа color и datetime этот способ не поможет - нет для них специальных функций. А потому все равно придется прибегать к явному приведению:
цитата:
color old_color=(color)ObjectGetInteger(0, ObjName, OBJPROP_COLOR); datetime old_startTime=(datetime)ObjectGetInteger(0, ObjName, OBJPROP_TIME, 1);
Тем не менее, второй способ выгоднее тем, что делает код более универсальным. В будущем такой код будет проще портировать в MQL5.
Отправлено: 17.11.14 23:12. Заголовок: Хочу сделать контрол..
Хочу сделать контроль тестового времени эксперта с использованием глобальных переменных. Проблема в этой строке if (!GlobalVariableGet(ControlTimeExpert, TimeExpertControl)) return; // Вызов гл.пер. Если ставлю &TimeExpertControl идет ошибка, а без & срабатывает return. Возможно есть еще ошибки, не знаю.
string ControlTimeExpert; double TimeExpertControl; int j_TimeExpertControl; datetime LastBar;
if (LastBar != iTime(NULL,PERIOD_D1,0)) // Если новый день, то делаем проверку { if (!GlobalVariableCheck(ControlTimeExpert)) // Если гл.пер. нет, то создаем GlobalVariableSet(ControlTimeExpert,TimeCurrent()); // Время первого запуска советника if (!GlobalVariableGet(ControlTimeExpert, TimeExpertControl)) return; // Вызов гл.пер. j_TimeExpertControl=(int)TimeExpertControl; if (TimeCurrent()>j_TimeExpertControl+7*24*60*60) // 7 суток на проверку { Alert("Время тестирования советника истекло"); return; } } LastBar = iTime(NULL,PERIOD_D1,0);
Отправлено: 18.11.14 10:12. Заголовок: На вскидку код верны..
На вскидку код верный, если подразумевать, что приведен только участок кода, а не весь код. Если же это весь код, тогда проблема в том, что переменная ControlTimeExpert не инициализирована. В ней нет названия глобальной переменной, отсюда и проблемы.
А почему выбран такой странный способ контроля? Ведь глобальную переменную пользователь может удалить вручную, что сведет на нет всю защиту. Лучше прописывать абсолютную дату окончания периода тестирования в самом коде. При отсылке конкретному пользователю просто перекомпилировать эксперт:
Отправлено: 18.11.14 10:35. Заголовок: Для отдельных пользо..
Для отдельных пользователей проблем нет. Но хочу разместить полнофункциональную демо версию на сайте и не заморачиваться под каждого клиента.
Scriptong пишет:
цитата:
На вскидку код верный, если подразумевать, что приведен только участок кода, а не весь код. Если же это весь код, тогда проблема в том, что переменная ControlTimeExpert не инициализирована.
Вообще то это весь код. Но кажется я понял. string ControlTimeExpert= "ControlTimeEA"; Теперь задана как название гл.переменной в начале. Попробую.
Остался вопрос: Чтобы осознать не бесполезность своих действий, подскажите где хранятся глобальные переменные? Я к примеру не знаю, думаю и большинство трейдеров тоже.
Остался вопрос: Чтобы осознать не бесполезность своих действий, подскажите где хранятся глобальные переменные? Я к примеру не знаю, думаю и большинство трейдеров тоже.
Сергей, список появится при нажатии в терминале клавиши F3, его можно менять и удалять.
Могу добавить, что время тестового периода явно прописанное в программе, по крайней мере в старых билдах интерпретатора, видно при открытии файла в редакторе (типа FAR, например). Т.е получив сообщение о том, что тестовый период истек - нажимается F4, поиск по дате, а потом год меняется с 2014 на 3014... ву а ля. Поэтому после компиляции имел смысл обработать код программой защиты от декомпиляции - программой типа ex4_protector.
Сообщение: 947
Зарегистрирован: 04.03.13
Откуда: Москва
Репутация:
2
Отправлено: 18.11.14 13:45. Заголовок: Перечитай мой пост ..
Sergey пишет:
цитата:
Хреново! Идея была неплохой, как мне казалось. Развалилась простым нажатием F3. У кого есть идеи по-лучше?
Перечитай мой пост выше - я его дополнил. Достаточно эффективно - перенос части кода в dll. Хотя в защите, как и во всем, лучше соизмерять затраты на защиту с доходами от продажи.
Отправлено: 18.11.14 13:57. Заголовок: А если в коде пропис..
А если в коде прописать создание отдельного файла хранящего информацию о времени. И затем, при необходимости, вызывать эти данные. Такое возможно? Если да, то где об этом почитать?
Сообщение: 948
Зарегистрирован: 04.03.13
Откуда: Москва
Репутация:
2
Отправлено: 18.11.14 14:02. Заголовок: Sergey пишет: А есл..
Sergey пишет:
цитата:
А если в коде прописать создание отдельного файла хранящего информацию о времени. И затем, при необходимости, вызывать эти данные. Такое возможно? Если да, то где об этом почитать?
тогда надо будет шифровать данные в файле или подписывать, иначе их можно просто поменять. А чем плох вариант Игоря? Или есть желание менять только файл лицензии с демо на коммерческий без замены самой программы?
Отправлено: 18.11.14 15:27. Заголовок: Genry пишет: А чем..
Genry пишет:
цитата:
А чем плох вариант Игоря?
Этот вариант я знаю и применяю. Но он больше подходит под отдельного пользователя. А хочется не заморачиваться под каждого. Дать возможность пользователям скачивать, но автоматически ограничивать время с начала первого запуска.
Если все элементы секрета находятся у злоумышленника - то взлом это вопрос времени, добавит трудностей взломщику перенос части кода в dll. Наиболее стойкая защита - это когда разделен и секрет, и алгоритм работы программы. Здесь повторюсь: надо соизмерять собственные затраты на защиту (и неудобство от ее применения - например, пользователь не понимая значения файла с датой его случайно удалил, получил сбой в торговле большими деньгами и выкатил претензию) с доходами от продажи.
Сообщение: 950
Зарегистрирован: 04.03.13
Откуда: Москва
Репутация:
2
Отправлено: 18.11.14 16:44. Заголовок: Sergey пишет: А хоч..
Sergey пишет:
цитата:
А хочется не заморачиваться под каждого. Дать возможность пользователям скачивать, но автоматически ограничивать время с начала первого запуска.
Сергей, это путь сопряжен с различными проблемами. Отследить внешний файл и удалить его трудностей не составит, и снова наступил 1 запуск. Лучше сделать полноценное Демо для какого-то экзотического инструмента, а остальные валюты - в коммерческой версии. Короче дать полное представление о возможностях работы и ограничить по функционалу. Например история берется только за несколько дней назад, а не вся. Или работать будет только на Демо-счете или закрыт прогон в тестере. Вот и будут две версии, одна - демо доступная всем и всегда, вторая - коммерческая, которая берется с закрытого раздела сайта после оплаты или еще как-нибудь
Сергей, это путь сопряжен с различными проблемами. Отследить внешний файл и удалить его трудностей не составит
Чисто с психологической точки зрения, не многие поймут, что ограничение можно снять удалив файл или гл.переменную. Именно потому, что это может быть так просто. Одни по незнанию, другие от большого знания.
Genry пишет:
цитата:
Лучше сделать полноценное Демо для какого-то экзотического инструмента, а остальные валюты - в коммерческой версии. Короче дать полное представление о возможностях работы и ограничить по функционалу. Например история берется только за несколько дней назад, а не вся. Или работать будет только на Демо-счете или закрыт прогон в тестере.
Этот стандартный подход хотелось немного дополнить.
А что касается 1% спецов, то любая защита для них не проблема. И вряд ли они могут заинтересоваться моими продуктами.
Отправлено: 18.11.14 21:08. Заголовок: Наиболее оптимальный..
Наиболее оптимальный способ демо-версии для советников - это пожизненная демо-версия для демо-счетов. В MQL4 тип счета определяется так:
цитата:
ENUM_ACCOUNT_TRADE_MODE accountType = (ENUM_ACCOUNT_TRADE_MODE)AccountInfoInteger(ACCOUNT_TRADE_MODE); switch (accountType) { case ACCOUNT_TRADE_MODE_DEMO: Print("Демо-счет"); break; case ACCOUNT_TRADE_MODE_CONTEST: Print("Конкурсный счет"); break; case ACCOUNT_TRADE_MODE_REAL: Print("Реальный счет"); break; }
Для индикаторов и скриптов придется придумывать что-то другое. Как вариант, если есть свой сайт, то можно проверять лицензию через WebRequest. Если же распространение не через сайт, то вполне достаточно того варианта, который я предложил в своем предыдущем посте. Перекомпиляция программы перед отправкой - секундное дело, больше времени потратите на отправку письма.
Отправлено: 19.11.14 21:51. Заголовок: Sergey пишет: Идея ..
Sergey пишет:
цитата:
Идея была в защите демо-версии от копировальщиков ордеров.
Против лома нет приема, т. е. универсального способа. Поэтому потрудитесь защищать каждую версию индивидуально. В этом нет ничего сложного. Не думаю, что поток запросов на демо-версии больше, чем десяток в день (это огромная цифра!). А для каждого из этих запросов в день у Вас будет одна версия. Новый день - следующая версия. Скомпилили - раскидали по запросам.
Отправлено: 24.11.14 17:39. Заголовок: Столкнулся с такой п..
Столкнулся с такой проблемой. При выводе StopLevel = MarketInfo(Symbol(), MODE_STOPLEVEL)*Point; // текущий уровень стопов через Alert StopLevel=0.0 Однако в реалии брокер не дает устанавливать уровень столосс ближе 30 pip на пятизнаке.(Пробовал в ручную перетащить не получилось.) При этом TP перетащить на Ask для Buy ордеров можно. Получается, что функция проверки расчета уровней SL и TP и корректной установки или модификации ордеров, использующие StopLevel в качестве минимального уровня - бутафория. Как выяснить действительный уровень? И почему они разные для SL и TP. Даже с учетом спреда ни чего не стыкуется. Спред всего 10-15 pip.
Столкнулся с такой проблемой. При выводе StopLevel = MarketInfo(Symbol(), MODE_STOPLEVEL)*Point; // текущий уровень стопов через Alert StopLevel=0.0 Однако в реалии брокер не дает устанавливать уровень столосс ближе 30 pip на пятизнаке.
Этим грешит Alpari. Возможно, есть другие брокеры. Стоплевел у них завуалированный - устанавливать стопы и отложки не ближе, чем 2 спреда. В своей библиотеке пришлось извратится следующим образом:
// Коррекция Stop Level ля тех ДЦ, в которых его вроде бы нет (но на самом деле есть - скрытый) и для тех ДЦ, у которых есть. Для последних увеличивается на тик для повышения надежности if (m_symbolInfo.stopLevel == 0) { if (!m_isECN) m_symbolInfo.stopLevel = NormalizeDouble(2 * m_symbolInfo.spread, m_symbolInfo.digits); } else m_symbolInfo.stopLevel = NormalizeDouble(m_symbolInfo.stopLevel + m_symbolInfo.tickSize, m_symbolInfo.digits);
Здесь m_isECN указывает программе, что нулевому стоплевелу можно верить. В противном случае используется вариант для Альпари.
В самую точку. Счета стандарт. Еще слышал об Альфа-банке. Ситуацию понял. Но предложенный подход тоже не идеален. Во-первых потому, что спред плавающий, а m_symbolInfo.stopLevel возможно постоянный. Во-вторых под одну гребенку меряем все ДЦ с m_symbolInfo.stopLevel=0. Созрела такая идея: Первоначальную информацию о m_symbolInfo.stopLevel получаем в int OnInit(). Далее при не удачной установке или модификации ордеров с ошибкой 130, запускаем функцию расчета m_symbolInfo.stopLevel в теле программы. Однако возникает новая проблема: Если m_symbolInfo.stopLevel величина постоянная - увеличение лучше делать по-шагово, скажем + 2pip. Один раз рассчитал и дальше проблем нет. А если плавающая и зависящая от спреда, то как предложено выше, но на каждом тике. И при этом нужно четко знать коэффициент увеличения. Выходит нужен дополнительный механизм получения информации.
Отправлено: 25.11.14 18:42. Заголовок: Sergey пишет: Но п..
Sergey пишет:
цитата:
Но предложенный подход тоже не идеален.
Подход не идеален лишь потому, что от пользователя требуется правильная установка параметра m_isECN. Если пользователь укажет, что счет относится к ECN, а это на самом деле не так, то советник не сможет открыть ни одного ордера, если стопы/профиты располагаются слишком близко к базовой цене ордера.
Sergey пишет:
цитата:
Во-первых потому, что спред плавающий, а m_symbolInfo.stopLevel возможно постоянный
Плавающий спред сейчас у большинства брокеров. Это нормально, и никак не влияет на правильную работу программы. Указанный мною код должен выполняться в начале каждого тика. Таким образом, информация постоянно обновляется. Насчет постоянного стоплевела не видел заверений ни у одного брокера. Такие нюансы почему-то не расписываются даже в договорах на 34-х страницах, а надо бы. Поэтому постоянный стоплевел мною воспринимается как несбыточная мечта, что и заставляет постоянно мониторить его размер (кроме, разве что, среды тестера).
Sergey пишет:
цитата:
Во-вторых под одну гребенку меряем все ДЦ с m_symbolInfo.stopLevel=0.
Нет. Я ведь указал на параметр m_isECN.
Sergey пишет:
цитата:
Далее при не удачной установке или модификации ордеров с ошибкой 130
К сожалению, получение ошибки №130 не дает нам гарантии того, что мы оперируем неправильным стоплевелом. Она, к примеру, может говорить о том, что тип исполнения Market Execution и мы пытаемся установить стопы/профиты в момент открытия рыночного ордера. Правда, это не очень удачный пример, т. к. тип исполнения уже можно узнать в новом MQL4. А вот тип счета (ECN или стандарт) программно узнать невозможно. Отсюда и куча проблем с этим стоплевелом.
Sergey пишет:
цитата:
Выходит нужен дополнительный механизм получения информации.
Остается лишь надеяться на то, что в язык будет добавлена соответствующая функция, которая позволит программе самой определить тип счета, а значит и способ расчета Stop Level.
Отправлено: 26.11.14 20:03. Заголовок: Sergey пишет: Я не ..
Sergey пишет:
цитата:
Я не о счетах ECN. Я о брокерах, которые реально выдерживают Stop Level=0 на других счетах.
Возможно, я неправильно назвал параметр, ошибочно предполагая, что нулевой стоплевел есть только на счетах типа ECN или STP. То есть речь только о неудачном названии, но не о сути параметра. Смысл в том, чтобы пользователь поставил его в "Да", когда у брокера реально нулевой стоплевел.
Посмотрел, как видно этот параметр в списке входных параметров. Получается не так уж и двузначно, вопрос конкретный: "Установить нулевой StopLevel?"
Смысл в том, чтобы пользователь поставил его в "Да", когда у брокера реально нулевой стоплевел.
Я уже сообразил. Но в место да-нет решил установить коэффициент отступа в спредах, если счета не ECN. Предполагая, что отступ не всегда равен двум спредам, даю возможность настраивать StopLeve пользователю под любого брокера.
Отправлено: 30.11.14 20:45. Заголовок: Sergey пишет: Но в ..
Sergey пишет:
цитата:
Но в место да-нет решил установить коэффициент отступа в спредах, если счета не ECN.
Достаточно веское замечание. Ведь два спреда советует только Alpari. У других брокеров может быть иное значение. И тут уже разворачиваем фантазию дальше: что, если брокер нам заявит, что отступ в спредах также не постоянный? Хотя это, конечно, уже вообще беспредел, мухлеж чистой воды. От таких "брокеров" нужно уходить сразу же после подобного ответа.
Отправлено: 03.12.14 20:19. Заголовок: Вернусь к старой тем..
Вернусь к старой проблеме.
Scriptong пишет:
цитата:
Перекомпиляция программы перед отправкой - секундное дело, больше времени потратите на отправку письма.
Genry пишет:
цитата:
Поэтому после компиляции имел смысл обработать код программой защиты от декомпиляции - программой типа ex4_protector.
Есть у кого нибудь рабочая версия перекомпилятора (free)? Скачал несколько версий ex4_protector, но все время выскакивают ошибки. Вроде все просто, но не получается.
Отправлено: 03.12.14 20:27. Заголовок: Sergey пишет: Есть ..
Sergey пишет:
цитата:
Есть у кого нибудь рабочая версия перекомпилятора (free)? Скачал несколько версий ex4_protector, но все время выскакивают ошибки. Вроде все просто, но не получается.
К сожалению, никогда не пользовался подобными "защитниками". Могу лишь сделать предположение о том, что эта версия разработана для старой версии MQL4. Для новой версии MQL4 подобные дополнительные защиты не нужны - новый компилятор на выходе выдает нативный код, который не так уж и легко взломать.
Даже если его и взломают, то почему таким профи будет не под силу взломать любую другую защиту, тем более распространяемую в сети?
Также учтите следующий момент. В новом MQL4 добавлены возможности ООП. А когда код написан объектно-ориентированным способом, то его декомпиляция в первозданный вид становится практически невозможной - слишком много различных вариантов, ни один современный компьютер не переберет. То есть взломщикам придется иметь дело не с декомпилированным вариантом, а именно с нативным кодом. Это затруднит их работу.
Отправлено: 04.12.14 17:18. Заголовок: Sergey пишет: Что т..
Sergey пишет:
цитата:
Что такое написание кода объектно-ориентированным способом?
Использование классов. Для этого любая задача разбивается на две и более подзадачи (как представляется удобнее для конкретного случая). Это подзадачи первого уровня. Они оформляются в виде классов, замкнутых в себе. Для передачи данных между этими классами создаются интерфейсы, которые гарантируют целостность данных в пределах одного класса, т. е. данные класса имеет право изменять только сам класс, и никто другой.
Каждая задача первого уровня дробится на более мелкие задачи. В зависимости от степени дробления задачи второго уровня оформляются в виде классов, используемыми классами первого уровня, или в виде функций (методов) существующих классов.
Простые задачи решать путем ООП, чаще всего, невыгодно. Но как только возникает задача хотя бы среднего уровня выигрыш от использования ООП становится очевидным.
Спасибо. Конечно, с примерами было бы лучше, но в целом понятно.
К сожалению, одними примерами не отделаться. На эту тему пишут книги по 300-400 страниц. Классы неплохо описаны у Шилдта, даже несмотря на то, что это справочник, а не полноценный учебник. Читайте с 237-ой страницы. Там, конечно, все про C++, но почти все справедливо и для современного MQL4. Если что-то будет непонятно, спрашивайте.
Отправлено: 02.02.15 10:14. Заголовок: Можно ли объекты тип..
Можно ли объекты типа ARROW привязавать к таким координатам? Ошибка не выдается, однако объект не отображается. Объект нужно отобразить в окне графика справа от него.
Отправлено: 13.02.15 09:42. Заголовок: Нужно ограничить дем..
Нужно ограничить демку по валютной паре. Однако некоторые ДЦ используют, как мне сказали, префиксы и суффиксы. Я с этим не сталкивался, а потому проверить правильность кода не могу. Прошу дать квалифицированную оценку.
Отправлено: 09.03.15 16:25. Заголовок: Сейчас в темах затро..
Сейчас в темах затронуты уровни фибоначчи. Я раньше не сталкивался с проекцией. Она рисуется по 3 точкам. Как уровни проекции рассчитать математически для использования в советниках.
Отправлено: 09.03.15 18:44. Заголовок: Sergey пишет: Нет п..
Sergey пишет:
цитата:
Нет проекция
Этот объект называется "Расширение Фибоначчи"
Расширение представляет собой совокупность двух объектов "Линии Фибоначчи":
На рисунке:
1. Красные линии - линии от расширения Фибо. 2. Зеленая - от линий Фибо, которая совпадает с первой красной линией расширения. 3. Темно-желтая - от линий Фибо, которая совпадает со второй линией расширения.
То есть мы взяли первый диапазон цен (зеленые линий Фибо и две первые точки расширения Фибо), потом в произвольном месте определили третью точку расширения (как бы откат), а затем хотим найти, куда будет двигаться цена, если за основу взять высоту волны от первых двух точек. Для этого взяли еще один объект "Линии Фибо" с таким же расстоянием между 0 и 100, как у первого объекта, но за ноль приняли третью точку расширения Фибо.
То есть мы взяли первый диапазон цен (зеленые линий Фибо и две первые точки расширения Фибо), потом в произвольном месте определили третью точку расширения (как бы откат), а затем хотим найти, куда будет двигаться цена, если за основу взять высоту волны от первых двух точек. Для этого взяли еще один объект "Линии Фибо" с таким же расстоянием между 0 и 100, как у первого объекта, но за ноль приняли третью точку расширения
Все понял. Спасибо. Расчет делаем по первым двум точкам, а отсчитываем от третьей.
Посылает электронное письмо по адресу, указанному в окне настроек на закладке "Почта".
Пример вызова: if (alertsEmail) SendMail("Message from MQL-Expert ", " Тrend UP");
bool SendMail( string subject, // заголовок string some_text // текст письма );
Параметры
subject
[in] Заголовок письма.
some_text
[in] Тело письма.
Возвращаемое значение
true – если письмо поставлено в очередь на отсылку, иначе возвращает false.
Примечание
Отсылка может быть запрещена в настройках, также может быть не указан адрес электронной почты. Чтобы получить информацию об ошибке, необходимо вызвать функцию GetLastError().
При работе в тестере стратегий функция SendMail() не выполняется.
Да, только предварительно необходимо настроить параметры почты в терминале. Когда первый раз с этим разбирался, то дня два мучался В итоге все это описал в статье Сигнальные уровни.
Отправлено: 16.04.15 18:48. Заголовок: Scriptong пишет: В ..
Scriptong пишет:
цитата:
В итоге все это описал в статье Сигнальные уровни.
Спасибо! Взял на заметку нюансы.
Я решил написать советник для ручной парной торговли. Но не хочется изобретать велосипед. Тем более, что по первому разу получается не очень ... Игорь, есть ли у вас на примете готовый открытый код, подобный функции "Торговля в один клик" в терминале МТ4. Буду очень благодарен за помощь. Еще интересует такой вопрос - как в кнопке сделать надпись в две строчки. Спасибо.
Игорь, есть ли у вас на примете готовый открытый код, подобный функции "Торговля в один клик" в терминале МТ4
То, что есть, уже безнадежно устарело (к примеру, Графическое управление экспертом), т. к. основано на зацикливании экспертов. В новом MQL4 такие вещи решаются без зацикливания, используя события, т. е значительно проще.
Sergey пишет:
цитата:
Еще интересует такой вопрос - как в кнопке сделать надпись в две строчки.
Кнопка в MQL4 - это потомок класса CChartObjectText, основанном на графическом объекте Label. Поэтому можно наследовать свой объект от кнопки, в котором сделать эту кнопку, состоящей из двух Label, стоящих одна под другой. Если же неохота влезать в дебри ООП, то можно в область отображения кнопки добавить еще один Label, под основной надписью. Но в коде такой вариант будет выглядеть некрасиво, да и пользоваться им будет неудобно - всегда необходимо помнить о том, что при изменении свойств кнопки следует изменить свойства второго Label. При работе с ООП такая необходимость отпадет само собой.
Отправлено: 20.04.15 16:00. Заголовок: Пока приходит в голо..
Пока приходит в голову только вариант со своим полем ввода. То есть использовать OBJ_LABEL (или OBJ_TEXT), для которого подписаться на события нажатия клавиш (обработчик OnChartEvent, событие CHART_EVENT_KEYDOWN). В обработчике проверяется код нажатой клавиши (из параметра lparam) и, если это цифра или точка, то символ копируется в объект. Иначе- пропускается. Но для такого поля ввода не совсем понятно, как сделать, чтобы был виден курсор, да еще и мигал.
Для других вариантов нужно смотреть класс CButton (MQL4\Include\Controls\Button.mqh) и думать, есть ли варианты по наследованию и переделке класса.
Отправлено: 05.05.15 18:08. Заголовок: Есть ли варианты! Ну..
Есть ли варианты! Нужно чтобы созданные индикатором объекты (вертикальные линии) не перерисовывались при смене ТФ, но удалялись при удалении индикатора с графика. Хочу задать диапазон расчета индикатора, который бы устанавливался перетаскиванием линий и не менялся при смене ТФ.
Скорее наоборот. DeleteAllObjects отбирает объекты по префиксу, а у вертикальных линий их нет.
То есть индикатор создает объекты с префиксом. Эти объекты нужно удалять при каждой деинициализации. Также индикатор создает два объекта без префикса. Такие объекты нужно удалять только в случае удаления индикатора с графика. Такая вот логика выходит.
То есть индикатор создает объекты с префиксом. Эти объекты нужно удалять при каждой деинициализации. Также индикатор создает два объекта без префикса. Такие объекты нужно удалять только в случае удаления индикатора с графика.
Верно. Вроде все просто, но по функционалу получилось круто. Огромное спасибо за помощь!
Отправлено: 15.05.15 07:30. Заголовок: Иногда сталкиваюсь с..
Иногда сталкиваюсь с проблемами, когда при компиляции ошибок не выдается, но индикатор не работает должным образом или сильно тормозит комп. (при смене ТФ, смене символа, перезагрузки компа). Причины могут быть разные - не верно заданные размеры массивов, нехватка глубины исторических данных и много чего еще. Такие ошибки я ищу с помощью меток (Alert). Существует ли другая технология поиска скрытых ошибок? Как пользоваться "Отладкой" - слово обнадеживающее, а функционал не понятен. Где обо всем об этом можно узнать?
Существует ли другая технология поиска скрытых ошибок?
Технология одна и та же - как можно подробнее вывести в журнал значения переменных и проследить по этим сообщениям маршрут выполнения программы. Если программа достаточно большая, то сначала распечатываются данные по основным блокам с целью нахождения проблемного блока, а затем переход на более низкий уровень (внутри проблемного блока) распечатки значений. И так до тех пор, пока не будет найдена ошибка.
Sergey пишет:
цитата:
Как пользоваться "Отладкой" - слово обнадеживающее, а функционал не понятен. Где обо всем об этом можно узнать?
Первоисточник описания всегда следует искать в том месте, где находится функционал, требующий описания. Так как отладчик является частью Meta Editor, то необходимо зайти в пункт меню "Справка" ME, нажать "Вызов справки", а затем просмотреть содержание. В данном случае путь к описанию таков: MetaEditor -> Разработка программ -> Отладка. Там дана первичная информация, так сказать, общее описание. Более подробно пример работы с отладчиком описан в статье "Отладка программ на MQL5". Отладка в МТ4 и МТ5 - процесс практически идентичный.
На данный момент проблема отладки - невозможность использования ее в тестере. Поэтому, чаще всего, отладчик оказывается не у дел.
Отправлено: 18.05.15 11:23. Заголовок: Как прогнать индикат..
Как прогнать индикатор в тестере на истории? Теоретически нужно запустить советник в режиме визуализации не выставляющий ордера и к графику прикрепить тестируемый индикатор. Есть ли еще варианты? Просто не все индикаторы ставятся таким образом на график.
Отправлено: 18.05.15 14:42. Заголовок: Sergey пишет: Есть ..
Sergey пишет:
цитата:
Как прогнать индикатор в тестере на истории? Теоретически нужно запустить советник в режиме визуализации не выставляющий ордера и к графику прикрепить тестируемый индикатор. Есть ли еще варианты? Просто не все индикаторы ставятся таким образом на график.
В МТ5 давно существует возможность полноценного тестирования индикаторов. А вот в МТ4 только-только появилось подобное. 810-й билд. Но пока это только бета-версия. Думаю, через пару-тройку недель состоится релиз и можно будет использовать новшество полноценно.
Отправлено: 30.08.15 09:15. Заголовок: Для экономии ресурсо..
Для экономии ресурсов компьютера расчеты некоторых индикаторов делаю на открытии бара.
if (LastBar == Time[0]) return(0);
int limit; int counted_bars=IndicatorCounted(); if(counted_bars>0) counted_bars--; limit=Bars-counted_bars; if (limit>ShowBars) limit=ShowBars; if (LastBarDay!=iTime(NULL,PERIOD_D1,0)) { ObDeleteObjectsByPrefix(PREFIX); limit=ShowBars; } int i; for (i = limit-1; i >= 0; i--)
Однако столкнулся с такой проблемой: После включения компа на следующий день, индикатор отрисовывается не верно. Как запрограммировать, чтобы при включении компа индикатор пересчитывал всю глубину истории, как при первом запуске. Прием типа if (LastBarDay!=iTime(NULL,PERIOD_D1,0)) { ObDeleteObjectsByPrefix(PREFIX); limit=ShowBars; } Не помогает...
Однако столкнулся с такой проблемой: После включения компа на следующий день, индикатор отрисовывается не верно. Как запрограммировать, чтобы при включении компа индикатор пересчитывал всю глубину истории, как при первом запуске.
В этой ветке народ обсуждал вопросы подкачки истории при перезагрузке терминала: http://forum.mql4.com/ru/40689 и ее влияние на работу индикаторов.
Отправлено: 31.08.15 13:01. Заголовок: Sergey пишет: Для э..
Sergey пишет:
цитата:
Для экономии ресурсов компьютера расчеты некоторых индикаторов делаю на открытии бара.
В индикаторах нет такой необходимости - делать проверку на открытие нового бара. Для этого у него есть IndicatorCounted() или prev_total и rates_total в новой версии MQL4. На основании этих данных необходимо определить, с какого бара следует обновить значения индикатора. В моих индикаторах обычно присутствует специальная функция:
цитата:
int GetRecalcIndex(int &total, const int ratesTotal, const int prevCalculated) { total = ratesTotal - /*здесь период индикатора или то, что его заменяет*/ - 2;
if (i_indBarsCount > 0 && i_indBarsCount < total) total = MathMin(i_indBarsCount, total);
Отправлено: 31.08.15 14:41. Заголовок: Scriptong пишет: В ..
Scriptong пишет:
цитата:
В индикаторах нет такой необходимости - делать проверку на открытие нового бара.
Но мне нужно, чтобы расчет на нулевом баре был произведен только на его открытии. А в случае return (MathMin(ratesTotal - prevCalculated, total)); как я понял, делается постоянный (по тиковый) расчет значений нулевого бара, но сам код возьму на вооружение. Спасибо.
Отправлено: 03.09.15 18:41. Заголовок: Sergey пишет: Но мн..
Sergey пишет:
цитата:
Но мне нужно, чтобы расчет на нулевом баре был произведен только на его открытии. А в случае return (MathMin(ratesTotal - prevCalculated, total)); как я понял, делается постоянный (по тиковый) расчет значений нулевого бара, но сам код возьму на вооружение. Спасибо.
Нет проблем:
цитата:
for (int i = limit; i > 0; i--) buffer[i - 1] = расчет
Отправлено: 01.09.15 18:46. Заголовок: Кажется наконец наше..
Кажется наконец нашел в чем проблема. Индикатор установлен на 12 валютных парах. Имя объекта string name = PREFIX + IntegerToString(leftTime); Однако бывает совпадение по времени разных графиков. Предполагаю, что при загрузке терминала обновление данных различных пар идет не синхронно по барам. В результате объекты с одинаковыми именами перерисовываются. Решение - ввел PREFIX, как настраиваемый параметр. Но это не совсем удобно. Можно привязать к символу, но трейдер может открыть несколько одинаковых графиков. Есть ли варианты?
Можно привязать к символу, но трейдер может открыть несколько одинаковых графиков. Есть ли варианты?
У каждого графика, даже если они одинаковые, есть его уникальный идентификатор, его возвращает функция ChartID. //--- get handle of the current chart long handle=ChartID();
Отправлено: 01.10.15 09:08. Заголовок: Игорь, в силу ряда р..
Игорь, в силу ряда реальных обстоятельств пришел к выводу, что брокеры учитывают алгоритм работы прибыльных советников появившихся в сети. Можно ли программно скрыть имя и настройки советника от брокера.
Игорь, в силу ряда реальных обстоятельств пришел к выводу, что брокеры учитывают алгоритм работы прибыльных советников появившихся в сети. Можно ли программно скрыть имя и настройки советника от брокера.
Думаю при необходимости (или при желании) брокер может со своей стороны через МТ получить доступ к файлам трейдера и выкачать необходимую информацию. Так что имеет смысл, получив прибыльного советника, с него вообще не торговать, а копировать его сигналы на пустой МТ где стоит только копировальщик сделок - имитируя ручное исполнение команд.
Отправлено: 01.10.15 12:31. Заголовок: Genry пишет: ак что..
Genry пишет:
цитата:
Так что имеет смысл, получив прибыльного советника, с него вообще не торговать, а копировать его сигналы на пустой МТ где стоит только копировальщик сделок - имитируя ручное исполнение команд.
Как вариант да, а еще можно выставить 0 магик, сойдет за ручную торговлю. Я торговал 5 месяцев с доходностью 40-80% в месяц и проблем не было, пока не выставил советник на продажу через mql5. Еще ровно месяц торговал, а затем все постепенно свелось к безубытку и что обидно, на демке, как и прежде все в ажуре, по крайней мере, результаты на много лучше. Не хочу отказываться от продаж, вот и ищу варианты.
Сообщение: 2034
Зарегистрирован: 04.03.13
Откуда: Москва
Репутация:
3
Отправлено: 01.10.15 18:13. Заголовок: Sergey пишет: Еще р..
Sergey пишет:
цитата:
Еще ровно месяц торговал, а затем все постепенно свелось к безубытку и что обидно, на демке, как и прежде все в ажуре, по крайней мере, результаты на много лучше.
Думаю при необходимости (или при желании) брокер может со своей стороны через МТ получить доступ к файлам трейдера и выкачать необходимую информацию.
Прямо теории заговора Неужели Вы всерьез думаете, что Meta Quotes предоставляют подобный сервис брокерам? Если бы такое было, то утечки информации не удалось избежать и давно появились бы скандалы. Более того, даже сами для себя Meta Quotes этого не сделают, потому как репутация дороже. Разного рода умельцы уже вдоль и поперек прочесали терминалы MT4 и MT5, несмотря на их хваленую защиту (не бывает абсолютной защиты). Если бы там был намек на выуживание информации, то Meta Quotes - не жилец.
Игорь, в силу ряда реальных обстоятельств пришел к выводу, что брокеры учитывают алгоритм работы прибыльных советников появившихся в сети. Можно ли программно скрыть имя и настройки советника от брокера.
Поверьте, вывод в корне неверный. Рынок - это достаточно сложная система, являющаяся надстройкой над социальными процессами. А социальные процессы - это сложнее, чем термоядерные реакции. Для справки: управляемые термоядерные реакции только разрабатываются, но еще далеки от массового использования.
Другое дело, что есть много брокеров, нечистых на руку, которые убивают прибыльные стратегии своим прямым вмешательством. Потому совет достаточно простой: торгуйте у нормальных брокеров (США, Канада, немного Западная Европа). Как только у брокера в регистрации видите какие-нибудь Виргинские о-ва - бегите от него.
Другое дело, что есть много брокеров, нечистых на руку, которые убивают прибыльные стратегии своим прямым вмешательством.
Все брокеры отслеживают работу своих клиентов - информация от источника в кругах брокера. Однако данные по вмешательству в работу трейдера предположительные по косвенным признакам. Появились советники в которых авторы вводят параметр скрывающий название эксперта от брокера. Идея перестраховаться будет не лишней. Но как это реализовать не знаю.
Появились советники в которых авторы вводят параметр скрывающий название эксперта от брокера. Идея перестраховаться будет не лишней. Но как это реализовать не знаю.
Тут придется немного попотеть. Схема такова: 1. Стратегия пишется в виде индикатора или неторгующего советника. 2. Все торговые операции выполняет специальный скрипт, который вызывается из программы (п. 1). 3. "Общение" между скриптом и программой производится через глобальные переменные, именованные каналы или специальную DLL.
Я такое делал в прошлом году. Подобный подход позволяет увеличить скорость отдачи торговых приказов в 8 раз (по числу доступных торговых потоков в МТ4) за счет их распараллеливания.
3. "Общение" между скриптом и программой производится через глобальные переменные, именованные каналы или специальную DLL.
Я предполагал наличие иного варианта, так как в mql5 запрещены dll и обращения к иным программам. Scriptong пишет:
цитата:
Я такое делал в прошлом году. Подобный подход позволяет увеличить скорость отдачи торговых приказов в 8 раз (по числу доступных торговых потоков в МТ4) за счет их распараллеливания.
Предложенный вариант тоже заинтересовал. Но для его реализации нужен пример (скажем при реализации советника на диверах) или более подробное описание (может в виде статьи).
Есть еще вопрос: Установка TP и SL путем модификации ордера. if (!OrderModify(OrderTicket(), OpPrice, SL, TP,0)) { Alert("Ошибка модификации ордера ",Type," = ",GetLastError()); return(false); }
Выскакивает ошибка - 139 Ордер заблокирован и уже обрабатывается
Получается, что ордер уходит на модификацию, но не получив ответ о результате модификации советник продолжает работать. И на последующих тиках выскакивают ошибки. Раньше такого не было. Какие существуют варианты решения этой проблемы?
Предложенный вариант тоже заинтересовал. Но для его реализации нужен пример (скажем при реализации советника на диверах) или более подробное описание (может в виде статьи).
К сожалению, там достаточно много кода получается. В статьях, которые бы читали другие (кратко и лаконично), его не опишешь.
Sergey пишет:
цитата:
Есть еще вопрос: Установка TP и SL путем модификации ордера. if (!OrderModify(OrderTicket(), OpPrice, SL, TP,0)) { Alert("Ошибка модификации ордера ",Type," = ",GetLastError()); return(false); }
Выскакивает ошибка - 139 Ордер заблокирован и уже обрабатывается
Скорее всего здесь речь идет о "заморозке" ордера. Это еще одно ограничение кухонь наряду со Stop Level. Называется Freeze Level. Его значение можно получить через:
цитата:
MarketInfo(_Symbol, MODE_FREEZELEVEL);
Если цена открытия отложенного ордера ближе к текущей цене, чем на уровень заморозки, то ничего с ордером уже нельзя будет сделать. То же самое касается, рыночного ордера, когда рынок подходит слишком близко к Stop Loss и Take Profit. В последние годы большинство брокеров устанавливают нулевой размер заморозки. Но, по всей видимости, еще остались динозавры .
Отправлено: 06.10.15 19:29. Заголовок: Да, Sergey пишет: Ч..
Да, Sergey пишет:
цитата:
Что же, придется ввести функцию корректной модификации ордера. и больше с ней не расставаться.
Да, для каждой торговой операции перед ее выполнением следует выполнять целый комплекс проверок на предмет корректности параметров. Если речь идет о модификации отложенного ордера, то список таков:
1. Если изменяется цена открытия ордера, то:
1.1 Проверить расстояние между текущей рыночной ценой и текущей ценой открытия на предмет попадания в коридор Freeze Level. 1.2 Проверить расстояние между рынком и новой ценой открытия на предмет попадания в коридор Stop Level. 1.3 Если не изменяются Stop Loss и Take Profit, то проверить, возможно ли перемещение цены открытия так, чтобы Stop Loss и Take Profit не оказались в коридоре Stop Level.
2. Если изменяется цена Stop Loss, то проверить расстояние от нового Stop Loss до новой цены открытия ордера. Если расстояние менее Stop Level, то модификация невозможна. 3. Если изменяется цена Take Profit, то проверить расстояние от нового Take Profit до новой цены открытия ордера. Если расстояние менее Stop Level, то модификация невозможна. 4. Если изменяется время истечения ордера, то проверить, не будет ли новое время слишком близко к текущему времени. Зазор должен быть не менее 600 секунд.
Отправлено: 14.01.16 14:16. Заголовок: Игорь, помоги, я в т..
Игорь, помоги, я в тупике. Индикатор рассчитывается по старшему ТФ (WorkTF) на периоде int ShowBars , но должен отрисовываться на графике младшего ТФ. Проблема с проверкой и подкачкой данных. При установке индикатора сразу на младший ТФ, ошибка выдается. А вот при смене ТФ со старшего на младший нет. Индикатор не удаляется, но и не отрисовывается. В чем причина не могу разобраться и, соответственно, исправить ошибку. int OnInit() { datetime New_dtBegin = iTime(NULL,WorkTF,ShowBars); if(!IsAllBarsAvailable(New_dtBegin)) { Alert("Не достаточна глубина истории баров. Индикатор удален."); return(INIT_FAILED); } return(INIT_SUCCEEDED); } //---- bool IsAllBarsAvailable(datetime dtBeginBar) { int lastBar = iBarShift(NULL, 0, dtBeginBar); if (GetLastError() == ERR_HISTORY_WILL_UPDATED) return (false); if(lastBar <= 0) return (false);
Отправлено: 22.01.16 12:27. Заголовок: Scriptong пишет: В ..
Scriptong пишет:
цитата:
В OnInit еще рано делать выводы о том, закачана история по нужному ТФ или нет. Проверить достаточность баров правильнее так:
На сколько я понял, пытаться подкачивать историю в OnInit не правильно. Тогда ошибка понятна. Исправил все с учетом рекомендаций, вроде работает. Огромное спасибо!
пытаться подкачивать историю в OnInit не правильно
Как раз правильно. В OnInit всегда стоит начать подкачку данных, просто обратившись в первому бару нужного таймфрейма. Но вот проверять результат там еще рано.
Игорь, а обращение к первому бару нужного таймфрейма запускает подкачку историии и в советниках тоже?
В MQL4 -да. При обращении к любому бару таймфрейма терминал, по идее, проверяет полноту истории по указанному символу/таймфрейму. Если какого-то бара нет, то запускается процесс подкачки истории, а вызванная функция генерирует ошибку, возвращая 0. Поэтому и используется подобный механизм проверки полноты истории. Но, сразу скажу, он не является идеальным, т. к. изначально не задумывался разработчиками именно таким образом. Поэтому "на все 100" надеяться на него не приходится. В MQL5 для решения этой проблемы есть специально разработанный способ получения данных с сервера.
Игорь, подскажи, как определить координату "y" в "окне" у осциллятора ( к примеру Sto), "окна" массштабируются, а координаты нет. Мне нудно отобразить значения показаний индикатора (объектами Wingdings) на всех ТФ в "окне" осциллятора.
Игорь, подскажи, как определить координату "y" в "окне" у осциллятора ( к примеру Sto), "окна" массштабируются, а координаты нет. Мне нудно отобразить значения показаний индикатора (объектами Wingdings) на всех ТФ в "окне" осциллятора.
Нужно больше информации. Что подразумевается под координатой Y? По моему пониманию, Y в подокнах - это значение индикатора. Также может быть значение в пикселях от одного из четырех углов подокна. И, кстати, уточните, какие исходные данные Вы хотите использовать для определения координат точки?
По моему пониманию, Y в подокнах - это значение индикатора.
Именно так. Текущее значение индикатора на всех ТФ в виде точки нужно отобразить под соответствующими надписями (М1.....MN) справа от индикатора текущего ТФ. Картинку я дал по Sto, но буду делать WPR . Осциллятор WPR ограничен значениями (-100-0). Я не знаю, как можно перевести значение индикатора в пиксели с учетом масштабирования индикатора. Единственная идея, которая мне пришла - это перевести координату Х надписи соответствующего ТФ в смещение показаний значения индикатора от нулевого бара. (Перевести координиту Х во время и рассчитать смещение в барах). Но я этого ни разу не делал, а возможно есть и другие способы. Нужна Ваша консультация - как грамотнее сделать.
Именно так. Текущее значение индикатора на всех ТФ в виде точки нужно отобразить под соответствующими надписями (М1.....MN) справа от индикатора текущего ТФ. Картинку я дал по Sto, но буду делать WPR . Осциллятор WPR ограничен значениями (-100-0). Я не знаю, как можно перевести значение индикатора в пиксели с учетом масштабирования индикатора. Единственная идея, которая мне пришла - это перевести координату Х надписи соответствующего ТФ в смещение показаний значения индикатора от нулевого бара. (Перевести координиту Х во время и рассчитать смещение в барах). Но я этого ни разу не делал, а возможно есть и другие способы. Нужна Ваша консультация - как грамотнее сделать.
Тут получается, что Х-координата должна быть в пикселях, а Y - в значениях индикатора. Таким образом, проблема решается преобразованием не Х-координаты, а Y-координаты. Х-координата должна быть известна всегда - это смещение столбца "таблицы" относительно правого верхнего угла подокна. Далее нужно преобразовать значение индикатора в пиксели для подокна. Для этого существует функция ChartTimePriceToXY. Только с ее помощью преобразуйте именно "цену" (так будет представляться значение индикатора) в Y. Время и, соответственно, Х в данном случае преобразовывать не нужно.
Я уже пробовал делать через нее. ChartTimePriceToXY(0, WindowFind(short_name),TimeCurrent(), SlowWPR, X_SlowWPR, Y_SlowWPR); Но координата У, как выяснилось, отсчитывается от верхней границы графика, а не подокна. Т.е если поднять окно до верхней граници графика, то все отображается, правда все равно со смещением по у. В нормальном же виде, данные даже не попадают в зону видимости подокна.
Чтобы использовать данный способ, надо как то определить координату У подокна в системе координат окна основного графика. Я не знаю, как это сделать.
Таким образом определяете координаты верхнего правого угла подокна относительно левого верхнего угла графика. А далее, получив координаты нужной точки, вычитаете из этих координат "нулевые" координаты.
Таким образом определяете координаты верхнего правого угла подокна относительно левого верхнего угла графика. А далее, получив координаты нужной точки, вычитаете из этих координат "нулевые" координаты.
Игорь, огромное спасибо! Идея понятна, реализация удалась.
Отправлено: 03.03.16 20:05. Заголовок: Игорь, есть вопрос, ..
Игорь, есть вопрос, но даже не знаю как его сформулировать, чтобы было понятно. Я сделал индикатор и советник на его основе. Обращение к данным индикатора сделал через iCustom. Теперь хочу встроить индикатор в советник. Проблема в том, что индикатор рассчитывается при помощи нескольких циклов, то есть нельзя взять и рассчитать нужные бары без циклов. В индикаторе, чтобы повторно не рассчитывать циклы используем limit = GetRecalcIndex(total, rates_total, prev_calculated); Как это можно реализовать в советнике?
Теперь хочу встроить индикатор в советник. Проблема в том, что индикатор рассчитывается при помощи нескольких циклов, то есть нельзя взять и рассчитать нужные бары без циклов.
Сегодня уже отвечал на подобный вопрос в другом месте (Недискретные рэндж-бары). Суть в том, что для каждого конкретного индикатора пишется свой собственный алгоритм расчета данных в советнике. В большинстве случаев такой алгоритм будет проще, если все сделать правильно.
Отправлено: 07.03.16 19:41. Заголовок: Scriptong пишет: В ..
Scriptong пишет:
цитата:
В большинстве случаев такой алгоритм будет проще, если все сделать правильно.
А как правильно? В смысле, какие есть варианты? К примеру, я сейчас просто сокращаю количество проходов по циклам до достаточного и вместо динамического массива использую статический, плюс ограничиваю расчет только открытием нового бара. Была идея перекопирования массива со смещением на одну позицию, тогда в расчет попадает только последний бар. Но запнулся на проверке. Ведь возможны пробелы в следствии, к примеру, разрыва связи с терминалом.
Отправлено: 10.03.16 17:36. Заголовок: Sergey пишет: А как..
Sergey пишет:
цитата:
А как правильно? В смысле, какие есть варианты?
Вариантов настолько много, что все их не перебрать. Проблема в том, что даже если я покажу пример встраивания индикатора в советник, то этот пример подойдет только для одного конкретного индикатора. Сделать по образу и подобию для другого индикатора не получится.
Общий смысл встраивания индикаторов, показания которых основаны на своих же предыдущих показаниях, заключается в повторении этой цепочки расчетов в советнике. Для этого не нужно создавать массив, длинной во всю историю котировок. Во многих случаях достаточно всего двух значений: предыдущего и текущего. Эти значения проходят по всей истории, передавая эстафету друг другу.
Подобным образом работают индикатор Divergence_Viewer и советник Divergence. Чтобы не мучаться каждый раз со встраиванием индикатора во советник, я разработал единый класс CDivergence, который подключается к любой программе.
Чтобы не мучаться каждый раз со встраиванием индикатора во советник, я разработал единый класс CDivergence, который подключается к любой программе.
Дааа! Пример явно выше моих познаний в программировании. Не думал, что все так сложно. Придется действовать по-старинке, решать проблемы по мере их поступления. Спасибо!
Дааа! Пример явно выше моих познаний в программировании. Не думал, что все так сложно. Придется действовать по-старинке, решать проблемы по мере их поступления. Спасибо!
Индикатор дивергенций - сам по себе достаточно сложный инструмент. По этой причине это действительно сложный для понимания пример.
Если есть какой-то простенький индикатор, его показания основаны на данных предыдущих баров и индикатор необходимо встроить в советник, то прикрепите его здесь. Я постараюсь показать, как это делается, чтобы желающие делать подобное самостоятельно хотя бы смогли понять сам принцип (в каком направлении думать).
По этой причине это действительно сложный для понимания пример.
Проблема не в сложности. Раньше ты практически к каждой строчки кода писал комментарий. Я просто учил программирование на примерах. В новом МТ введено много дополнительных параметров - класс, структура и т.д. Справочник не дает развернутого понимания их возможностей применения на примерах, он скорее рассчитан на профессионалов с кратким описанием, да еще с таким, что само описание требует к нему описание. Получается, что не представляя в целом возможностей того или иного параметра и не имея описания при его применении сложно понять, что к чему.
Раньше ты практически к каждой строчки кода писал комментарий.
Да, потому что раньше (на Адмирале) статьи писал именно для обучения других, т. е. в качестве примеров, т. к. была соответствующая договоренность с администрацией компании. Сейчас же подобных договоренностей ни с кем нет. Программы пишутся именно для использования, а не для примеров.
Sergey пишет:
цитата:
В новом МТ введено много дополнительных параметров - класс, структура и т.д. Справочник не дает развернутого понимания их возможностей применения на примерах, он скорее рассчитан на профессионалов с кратким описанием, да еще с таким, что само описание требует к нему описание. Получается, что не представляя в целом возможностей того или иного параметра и не имея описания при его применении сложно понять, что к чему.
Да, с обучением языкам MQL4 и MQL5 сейчас достаточно сложно, нет учебника, как было ранее для MQL4. Но возможности ООП в MQL точно такие же, как и в С++. Поэтому для освоения ООП достаточно прочитать соответствующие разделы в учебниках по С++. Также могу порекомендовать неплохую статью Дмитрия Федосеева. В ней он кратко описывает суть ООП. На мой взгляд, достаточно понятно.
Поэтому для освоения ООП достаточно прочитать соответствующие разделы в учебниках по С++. Также могу порекомендовать неплохую статью Дмитрия Федосеева. В ней он кратко описывает суть ООП. На мой взгляд, достаточно понятно.
#property indicator_separate_window #property indicator_buffers 1 #property indicator_color1 LightBlue #property indicator_width1 2 #property indicator_level1 50 //---- input parameters extern int Price = 0; //Applied Price(0-Close;1-Open;2-High;3-Low;4-Median;5-Typical;6-Weighted) extern int Length = 14; // Period of evaluation extern int Smooth = 3; // Period of smoothing extern int MA_Mode = 2; // Mode of MA //---- buffers double SmRSI[]; double vRSI[]; double vBulls[]; double vBears[]; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int init() { //---- indicators IndicatorBuffers(4); SetIndexStyle(0,DRAW_LINE); SetIndexBuffer(0,SmRSI); SetIndexBuffer(1,vRSI); SetIndexBuffer(2,vBulls); SetIndexBuffer(3,vBears);
//---- name for DataWindow and indicator subwindow label string short_name="VolumeRSI("+Price+","+Length+","+Smooth+","+MA_Mode+")"; IndicatorShortName(short_name); SetIndexLabel(0,"VolumeRSI");
//---- SetIndexDrawBegin(0,Length+Smooth);
return(0); }
//+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int start() { int shift, limit, counted_bars=IndicatorCounted(); double Price1, Price2, Bulls, Bears, AvgBulls, AvgBears; //---- if ( counted_bars < 0 ) return(-1); if ( counted_bars ==0 ) limit=Bars-1;
Отправлено: 21.04.16 17:24. Заголовок: Sergey пишет: В тер..
Sergey пишет:
цитата:
В терминале два отложенных ордера. Почему в первом случае выбирается только один ордер, а во втором как положено два.
Немного путаете: как положено, два ордера, будет выбираться только в первом случае. Потому что, если OrdersTotal() = 2, то будет обращение к ордерам с индексами 0 и 1 (нумерация ведется с нуля). Тут все верно.
А вот второй случай описан неправильно. Цикл тоже проходит две итерации (i = 2 и i = 1), но ордера с индексом 2 нет в списке рабочих. Поэтому OrderSelect возвращает false и правильно предостерегает от обращения к ордеру, который не выбран.
Немного путаете: как положено, два ордера, будет выбираться только в первом случае. Потому что, если OrdersTotal() = 2, то будет обращение к ордерам с индексами 0 и 1 (нумерация ведется с нуля). Тут все верно.
А вот второй случай описан неправильно. Цикл тоже проходит две итерации (i = 2 и i = 1), но ордера с индексом 2 нет в списке рабочих. Поэтому OrderSelect возвращает false и правильно предостерегает от обращения к ордеру, который не выбран.
В том то и проблема, что я ничего не путаю. Цикл удаления отложенных ордеров. В первом случае один ордер всегда остается в рынке, а вот во втором удаляются все. Я рассуждаю, как Вы. Вот и не могу понять , почему? Логически правильный первый вариант, а работает второй. Вот я и подумал, что возможно обращение идет не с 0, а 1 ордера. Но цикл с закрытием рыночных ордеров работает правильно именно по первому варианту.
Отправлено: 22.04.16 10:21. Заголовок: Sergey пишет: Цикл ..
Sergey пишет:
цитата:
Цикл удаления отложенных ордеров.
Теперь понятна проблема. Если требуется удалять/закрывать ордера, то следует использовать именно обратный цикл, как во втором случае. Только он должен выглядеть следующим образом:
цитата:
for (int i = OrdersTotal() - 1; i >= 0; i--)
Потому как при прямом переборе ордеров удаление любого ордера из середины списка приводит к изменению индексов всех остальных ордеров.
Простой пример. Есть три ордера с тикетами А, В и С. Соответственно у ордера А индекс в списке ордеров 0, у В - 1, у С - 2. Если идти прямым перебором, то сначала удаляем ордер А. Сразу после его удаления ордер В получает индекс 0, ордер С - 1. Но в цикле то мы переходим ко второй итерации (i = 1), т. е. к ордеру с индексом 1. В итоге удаляем ордер С и получаем окончание цикла. Выходит, что ордер В так и не будет удален.
Отправлено: 22.04.16 08:15. Заголовок: Кажется я разобрался..
Кажется я разобрался.... Проблема аналогична той, которую я описывал 03.10.2015. - взаимодействие сервера брокера и терминала. Но возможно я не прав, поэтому приведу код полностью. for (int j = 0; j < OrdersTotal(); j++) // Используется весь список ордеров if (OrderSelect(j, SELECT_BY_POS)) // Убедимся, что ордер выбран { Alert(OrderTicket()); if (OrderMagicNumber() == MagicNumber && OrderSymbol() == Symbol() // ордер должен принадлежать текущей валютной паре && OrderType()>1) if(!DeleteDeal(OrderTicket()))return; } //---- bool DeleteDeal(int ticket) { if ( OrderSelect(ticket, SELECT_BY_TICKET) && // Существует ордер с заданным.. OrderCloseTime() == 0 && // ..тикетом и ордер не закрыт ... OrderType()>1) // ордер отложенный { if (!WaitForTradeContext()) return(false); // Свободен ли торговый поток?
if (!OrderDelete(OrderTicket())) // Если ордер не удалось удалить, то результат { Alert(GetLastError()); return(False); // функции - False } } return(True); // Ордер удален } //---- Ошибки удаления или занятости торгового потока не выскакивают. Я выставил 8 отложенников - удалилось только 4. Alert при отборе ордеров даже не высветил их (не удаленных) тикеты. Этот глюк появился с 600 билдом - сервер еще не обработал ордер, а терминал продолжает отработку кода, при этом не выдает ошибки . С рыночными ордерами я эту проблему решил путем зацикливания функций закрытия и проверки ордеров.
Проблема аналогична той, которую я описывал 03.10.2015. - взаимодействие сервера брокера и терминала.
Нет. Взаимодействие здесь не при чем. Проблема лишь с нумерацией ордеров в списке. При проведении торговых операций список, конечно же, претерпевает изменения. Не стоит производить торговые операции в цикле, а по большому счету вообще не рекомендую в одном обработчике событий (OnTick, OnChartEvent, OnTimer) совершать более одной торговой операции. То есть вне зависимости от результата выполнения операции следует перемещать выполнение программы на начало обработчика события. Ведь за время выполнение торгового запроса программа "спала" (в компьютерном исчислении пара секунд - это неимоверно много), а ситуация могла кардинально измениться.
Отправлено: 22.04.16 09:33. Заголовок: К стати, проблему вз..
К стати, проблему взаимодействия сервера и терминала при модернизации ордеров, описанную мной 03.10.2015 (ордер не успевал обрабатываться сервером до следующего тика) пришлось решать так... if (!OrderModify(OrderTicket(), OpPrice, SL, TP,0)) { int Error = GetLastError(); if (Error!=139 && Error!=0) { Alert("Order modification error ",OrderTicket()," = ",Error); return(false); } }
ордер не успевал обрабатываться сервером до следующего тика
Если так, то советник никогда не узнает о приходе этого пропущенного тика. Пропущенные тики для советников теряются безвозвратно. Обработка тика советником происходит только в том случае, если советник закончил обработку предыдущего тика.
Если так, то советник никогда не узнает о приходе этого пропущенного тика. Пропущенные тики для советников теряются безвозвратно. Обработка тика советником происходит только в том случае, если советник закончил обработку предыдущего тика.
Здесь имелось ввиду, что по приходу следующего тика информация об ордере не поменялась. В результате идет повторная команда на модификацию ордера. И выдается ошибка 139 или 0.
Здесь имелось ввиду, что по приходу следующего тика информация об ордере не поменялась.
Это более, чем странно. Никогда такого в МТ4 не замечал, т. к. в нем все команды синхронные. Такое может быть только в МТ5, но там для контроля есть соответствующие события. В МТ4, если советник отправляет торговый приказ, то эксперт будет бездействовать до момента получения ответа от сервера. За это время советником не будут восприниматься какие-либо тики, т. к. советник "висит". Если же ответ получен, то вместе с этим будет получено новое состояние ордеров, если они изменились. Ошибка 139 может быть получена, если отправляется приказ на модификацию/удаление/закрытие ордера, который в данный момент обрабатывается сервером в результате достижения ценой уровня его открытия (если отложенный ордер) или уровня Stop Loss/Take Profit. Еще такое может быть, если брокер использует уровень заморозки. Но тогда это брокер-динозавр, т. к. я уже давно не встречал, чтобы Freeze Level отличался от нуля.
Отправлено: 22.04.16 21:00. Заголовок: Scriptong пишет: В ..
Scriptong пишет:
цитата:
В МТ4, если советник отправляет торговый приказ, то эксперт будет бездействовать до момента получения ответа от сервера. За это время советником не будут восприниматься какие-либо тики, т. к. советник "висит". Если же ответ получен, то вместе с этим будет получено новое состояние ордеров, если они изменились.
Вот и я так думал. И нормального объяснения этому у меня пока нет. Времени прошло много, всего точно не упомнишь. Знаю, что когда исключил ошибку 139, стала появляться ошибка 0 (модификация по тем же параметрам SL и TP). Причем, если исключить Alert, в журнале ошибка не проходит. Думаю, в свете тех рекомендаций, которые ты дал выше, причина может скрываться в сортировке ордеров. Модификация сделана в цикле перебора всех ордеров. А советник допускает наличие нескольких ордеров одновременно. Придется заменить простой перебор функцией слежения за ордерами.
Отправлено: 03.05.16 18:09. Заголовок: Столкнулся с непонят..
Столкнулся с непонятной ситуацией. Вот Журнал модификации ордера... .. из которого следует, что отправлено две заявки на модификацию ордера. Причем конечные значения модификации по ТР на 40 тиков отличаются от расчетных. Ошибок не выдается. Я поставил метки на количество расчетов ТР и модификаций, которые показали, что расчет и заявка на модификацию выполняются, как положено,один раз. У кого нибудь есть разумные объяснения?
Немного подробнее про ситуацию. Речь идет об общем журнале или о журнале экспертов? Также желательно видеть всю строку сообщения (можно обрезать название эксперта, если речь об автоторговле).
Нудно посчитать Profit при закрытии нескольких Sell ордеров. На сколько корректен такой алгоритм. for (int i = SellCount-1; i >= 0; i--) if (OrderSelect(SellTicket, SELECT_BY_TICKET) && OrderCloseTime() == 0) if (OrderClose(OrderTicket(), OrderLots(), NT(Ask), 3)) Profit +=OrderProfit(); Или после закрытия нужно заново вытаскивать ордер уже из истории и лишь затем подсчитывать профит.
Нудно посчитать Profit при закрытии нескольких Sell ордеров. На сколько корректен такой алгоритм. for (int i = SellCount-1; i >= 0; i--) if (OrderSelect(SellTicket, SELECT_BY_TICKET) && OrderCloseTime() == 0) if (OrderClose(OrderTicket(), OrderLots(), NT(Ask), 3)) Profit +=OrderProfit(); Или после закрытия нужно заново вытаскивать ордер уже из истории и лишь затем подсчитывать профит.
Нет, неправильно. Ведь SellCount уже было откуда-то взято. Значит, был цикл, который посчитал количество закрытых ордеров. Зачем тогда второй цикл, если все это можно было посчитать в одном цикле? Также непонятно, для чего представленный цикл нужен, если постоянно идет обращение к одному и тому же ордеру с тикетом SellTicket?
Подсчет прибыли/убытка некоторых закрытых ордеров осуществляется следующим образом:
цитата:
double profit = 0.0; for (int i = OrdersHistoryTotal() - 1; i >= 0; i--) { if (!OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)) continue; if (OrderType() != OP_SELL) continue; profit += OrderProfit() + OrderSwap() + OrderComission(); }
Также непонятно, для чего представленный цикл нужен, если постоянно идет обращение к одному и тому же ордеру с тикетом SellTicket?
SellTicket|i| это массив тикетов Sell-ордеров отобранных для закрытия, не заметил, что квадратные скобки удалились. Меня интересует корректность такой последовательности if (OrderClose(OrderTicket(), OrderLots(), NT(Ask), 3)) Profit +=OrderProfit() + OrderSwap() + OrderComission(); или все же так if (OrderClose(OrderTicket(), OrderLots(), NT(Ask), 3)) if (OrderSelect(OrderTicket(), SELECT_BY_TICKET,, MODE_HISTORY) Profit +=OrderProfit() + OrderSwap() + OrderComission();
Отправлено: 12.05.16 10:42. Заголовок: Sergey пишет: или в..
Sergey пишет:
цитата:
или все же так if (OrderClose(OrderTicket(), OrderLots(), NT(Ask), 3)) if (OrderSelect(OrderTicket(), SELECT_BY_TICKET,, MODE_HISTORY) Profit +=OrderProfit() + OrderSwap() + OrderComission();
Конечно же, так. Ведь в первом случае получаем данные непонятно какого ордера, т. к. перед обращением к функциям OrderXXX обязательно требуется выбор ордера при помощи OrderSelect.
Игорь, подскажи, можно ли с помощью обработчика"CHARTEVENT_OBJECT_ENDEDIT — событие окончания редактирования текста в поле ввода графического объекта LabelEdit" задавать советнику значения типа double? Если ДА и если не сложно, напиши пример.
Игорь, подскажи, можно ли с помощью обработчика"CHARTEVENT_OBJECT_ENDEDIT — событие окончания редактирования текста в поле ввода графического объекта LabelEdit" задавать советнику значения типа double? Если ДА и если не сложно, напиши пример.
параметр sparam был не строковый, а типа double? Если так, то нельзя такое делать. Да и не нужно. Ведь строку легко преобразовать в вещественное значение при помощи функции StringToDouble. Таким образом, алгоритм будет следующий:
цитата:
void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam) { if (sparam != MY_LABEL_EDIT) return; string text = ObjectGetString(0, sparam, OBJPROP_TEXT); double value = StringToDouble(text); }
Нет. К примеру я хочу изменить лот советнику на поле графика, не вызывая настройки советника. Конкретный пример- встроенная функция "Торговля в один клик". Лот можно менять набирая текст на клавиатуре. То есть мне нужно вывести часть настроек советника в таблицу на графике цены, так чтобы их можно было задавать, а они подхватывались советником, как будто были изменены в настройках.
Отправлено: 12.05.16 10:43. Заголовок: Sergey пишет: Нет. ..
Sergey пишет:
цитата:
Нет. К примеру я хочу изменить лот советнику на поле графика, не вызывая настройки советника. Конкретный пример- встроенная функция "Торговля в один клик". Лот можно менять набирая текст на клавиатуре. То есть мне нужно вывести часть настроек советника в таблицу на графике цены, так чтобы их можно было задавать, а они подхватывались советником, как будто были изменены в настройках.
Посмотрите сам пример. Именно этому случаю он и соответствует.
Отправлено: 30.06.16 11:29. Заголовок: Игорь, подскажи в че..
Игорь, подскажи в чем проблема.... Вот часть кода из советника #define NumOrd 1 // Количество элементов массива (стратегий) struct OrdInfo { double isPrice; double isSL; double isTP; double isLot; int isTicket; int isType; int isMagic; string isComment; }; OrdInfo g_ordInfo|NumOrd|; //---- void Terminal() { Qnt=0; // Счётчик количества ордеров //---- for(int i=0; i<OrdersTotal(); i++) // По рыночн. и отлож. ордерам { if(OrderSelect(i,SELECT_BY_POS)==true //Если есть следующ. && OrderSymbol()==Symbol() //.. и наша вал.пара && OrderMagicNumber()!=0 && OrderMagicNumber()<=NumOrd) //.. и он открыт экспертом { Alert("1"); g_ordInfo|i|.isPrice = OrderOpenPrice(); // Цена открытия ордера Alert("2"); g_ordInfo|i|.isSL=OrderStopLoss(); // Стоп-лосс ордера g_ordInfo|i|.isTP=OrderTakeProfit(); // Тейк-профит ордера g_ordInfo|i|.isLot=OrderLots(); // Количество лотов g_ordInfo|i|.isTicket=OrderTicket(); // Номер ордера g_ordInfo|i|.isType=OrderType(); // Тип ордера g_ordInfo|i|.isMagic=OrderMagicNumber(); // ID ордера g_ordInfo|i|.isComment=OrderComment(); // Комментарий ордера Qnt++; // Колич. ордеров } } }
Советник прекрасно работает в тестере стратегий. Однако в реале зависает между метками 1 и 2. Причем комп не виснет, в журнале ничего. Но тики не проходят.
Советник прекрасно работает в тестере стратегий. Однако в реале зависает между метками 1 и 2. Причем комп не виснет, в журнале ничего. Но тики не проходят.
Проблема в неправильной записи информации об ордерах в массив. Нумерация ордеров и нумерация элементов массива совпадает, а не должна бы. Поэтому в тестере и работает все прекрасно - там нет "чужих" ордеров, все свои.
Правильная организация цикла такая:
цитата:
for(int i=0; i<OrdersTotal(); i++) // По рыночн. и отлож. ордерам { if(OrderSelect(i,SELECT_BY_POS)==true //Если есть следующ. && OrderSymbol()==Symbol() //.. и наша вал.пара && OrderMagicNumber()!=0 && OrderMagicNumber()<=NumOrd) //.. и он открыт экспертом { g_ordInfo[Qnt].isPrice = OrderOpenPrice(); // Цена открытия ордера g_ordInfo[Qnt].isSL=OrderStopLoss(); // Стоп-лосс ордера g_ordInfo[Qnt].isTP=OrderTakeProfit(); // Тейк-профит ордера g_ordInfo[Qnt].isLot=OrderLots(); // Количество лотов g_ordInfo[Qnt].isTicket=OrderTicket(); // Номер ордера g_ordInfo[Qnt].isType=OrderType(); // Тип ордера g_ordInfo[Qnt].isMagic=OrderMagicNumber(); // ID ордера g_ordInfo[Qnt].isComment=OrderComment(); // Комментарий ордера Qnt++; // Колич. ордеров } }
Отправлено: 28.08.16 15:30. Заголовок: Нужно сделать описан..
Нужно сделать описание объекта "кнопка". Рядом с объектом "кнопка" Установил "OBJ_LABEL" - "?". Как сделать, чтобы при наведении на "?" высвечивалось описание , а не имя объекта с ценой? Если выложите готовый блок алгоритма, буду очень признателен.
Нужно сделать описание объекта "кнопка". Рядом с объектом "кнопка" Установил "OBJ_LABEL" - "?". Как сделать, чтобы при наведении на "?" высвечивалось описание , а не имя объекта с ценой? Если выложите готовый блок алгоритма, буду очень признателен.
Никакого алгоритма там нет. При создании кнопки нужно лишь воспользоваться назначением свойства всплывающей подсказки:
Спасибо, на конец разобрался. ObjectSetString(0, name, OBJPROP_TOOLTIP, "текст"); Оказывается упускал первый параметр (chart_id) в результате получал ошибку и не мог понять в чем дело.
Игорь, знаком ли ты с программой Forex Tester. Можно ли в ней тестировать индикаторы MQL4?
Да, и не только по наслышке. В 2009-ом году переводил для Forex Tester один из индикаторов MQL4. Тогда же писал рекламную статью для них в журнале Fortrader.ru (47-й номер)
Sergey пишет:
цитата:
Можно ли в ней тестировать индикаторы MQL4?
Нет, нельзя. Нужно переводить программы на Delphi или на C++. Но справедливости ради нужно сказать, что API Forex Tester'a намеренно копирует функционал MQL4. Там даже также функции называются. Поэтому чисто алгоритмически перевод не очень сложен.
OsMA_Handle = iOsMA(NULL,PERIOD_CURRENT ,FastEMA,SlowEMA,SignalSMA,applied_price); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Функция деинициализации | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { IndicatorRelease(OsMA_Handle); // удаляет хэндл индикатора и освобождает память занимаемую им ArrayFree(Up_OsMA_Buffer); // освобождаем динамический массив от данных ArrayFree(Dn_OsMA_Buffer); ArrayFree(OsMA_Buffer); } //==================================================================== //+------------------------------------------------------------------+ //| 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[]) { int calculated=BarsCalculated(OsMA_Handle); if(calculated<rates_total) { Alert("Not all data of OsMA_Handle is calculated (",calculated,"bars ). Error",GetLastError()); return(0); }
//--- we can copy not all data int to_copy; if(prev_calculated>rates_total || prev_calculated<0) to_copy=rates_total; else { to_copy=rates_total-prev_calculated; to_copy++; } //--- get OsMA_Buffer buffer if(IsStopped()) return(0); //Checking for stop flag if(CopyBuffer(OsMA_Handle,0,0,to_copy,OsMA_Buffer)<=0) { Print("Getting OsMA_Buffer is failed! Error",GetLastError()); return(0); }
//--- int k,limit; if(prev_calculated==0) limit=0; else limit=prev_calculated-1; //--- the main loop of calculations for(k=limit;k<rates_total;k++) { //Dn_OsMA_Buffer[k]=0.0; Up_OsMA_Buffer[k]=0.0; //--- calculate OsMA //if(OsMA_Buffer[k]>OsMA_Buffer[k+1]) //Up_OsMA_Buffer[k]=OsMA_Buffer[k]; //else Dn_OsMA_Buffer[k]=OsMA_Buffer[k];
Если вместо выше выделенного текста подставить нижнюю строку и (#property indicator_plots 1), то все работает, но в одном цвете. А так, нет. Отображается абра-кадабра какая-то.
Up_OsMA_Buffer[k]=OsMA_Buffer[k]; }
//--- return value of prev_calculated for next call return(rates_total); } //====================================================================
Что не правильно в выделенном тексте? А если задать ArraySetAsSeries(OsMA_Buffer,true); , то и этот вариант не работает.
Отправлено: 25.01.18 22:45. Заголовок: Sergey пишет: Что н..
Sergey пишет:
цитата:
Что не правильно в выделенном тексте? А если задать ArraySetAsSeries(OsMA_Buffer,true); , то и этот вариант не работает.
Дело в том, что без ArraySetAsSeries нумерация баров в таймсериях ведется слева направо по графику. То есть бар с индексом 0 - где-то глубоко в истории, а текущий бар - это rates_total - 1. Поэтому для такой нумерации нужно:
Начинать перебор баров не с бара 0, а с бара 1, т. к. нам нужно взять высоты гистограммы предыдущего бара, которого для бара 0 нет. То есть limit ставится не на 0, а на 1.
Понять, что предыдущий бар, это не k + 1, а k - 1.
OsMA_Handle=iOsMA(NULL,PERIOD_CURRENT,FastEMA,SlowEMA,SignalSMA,applied_price); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Функция деинициализации | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { IndicatorRelease(OsMA_Handle); // удаляет хэндл индикатора и освобождает память занимаемую им ArrayFree(Up_OsMA_Buffer); // освобождаем динамический массив от данных ArrayFree(Dn_OsMA_Buffer); ArrayFree(OsMA_Buffer); } //==================================================================== //+------------------------------------------------------------------+ //| 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[]) { int calculated=BarsCalculated(OsMA_Handle); if(calculated<rates_total) { Alert("Not all data of OsMA_Handle is calculated (",calculated,"bars ). Error",GetLastError()); return(0); }
//--- we can copy not all data int to_copy; if(prev_calculated>rates_total || prev_calculated<0) to_copy=rates_total; else { to_copy=rates_total-prev_calculated; to_copy++; } //--- get OsMA_Buffer buffer if(IsStopped()) return(0); //Checking for stop flag if(CopyBuffer(OsMA_Handle,0,0,to_copy,OsMA_Buffer)<=0) { Print("Getting OsMA_Buffer is failed! Error",GetLastError()); return(0); }
//--- int k,limit; if(prev_calculated==0) limit=1; else limit=prev_calculated-1; //--- the main loop of calculations for(k=limit;k<rates_total;k++) { Dn_OsMA_Buffer[k]=0.0; Up_OsMA_Buffer[k]=0.0; //-- calculate OsMA if(OsMA_Buffer[k]>OsMA_Buffer[k-1]) Up_OsMA_Buffer[k]=OsMA_Buffer[k]; else Dn_OsMA_Buffer[k]=OsMA_Buffer[k]; }
//--- return value of prev_calculated for next call return(rates_total); }
Отправлено: 26.01.18 07:35. Заголовок: Спасибо! Но хотелось..
Спасибо! Но хотелось бы разобраться до конца. Как изменить код с использованием ArraySetAsSeries(OsMA_Buffer,true); Поскольку именно этот вариант в дальнейшем будет использован в советниках и рекомендован во всех статьях, а у меня не вышел.
Отправлено: 26.01.18 17:44. Заголовок: Тогда нужно всю инде..
Тогда нужно всю индексацию развернуть, а не просто использовать ArraySetAsSeries. Т. к. цикл расчета данных для каждого бара в "правильном" индикаторе должен следовать слева направо по графику, то нужно идти от rates_total (limit поддерживать) до 0 с декрементом.
Тогда нужно всю индексацию развернуть, а не просто использовать ArraySetAsSeries. Т. к. цикл расчета данных для каждого бара в "правильном" индикаторе должен следовать слева направо по графику, то нужно идти от rates_total (limit поддерживать) до 0 с декрементом.
На словах я это понимаю, с практикой туго. Устанавливаем порядок индексации массива как в таймсерии if(CopyBuffer(OsMA_Handle,0,0,to_copy,OsMA_Buffer)<=0) { Print("Getting OsMA_Buffer is failed! Error",GetLastError()); return(0); } ArraySetAsSeries(OsMA_Buffer,true);
Как не пересчитываю слева-направо или наоборот, получается фигня. В чем не прав не знаю. Я это смогу понять, лишь проанализировав правильный код. Не зачти за лишний труд. Плиз!
Отправлено: 28.01.18 17:10. Заголовок: Sergey пишет: Как н..
Sergey пишет:
цитата:
Как не пересчитываю слева-направо или наоборот, получается фигня. В чем не прав не знаю. Я это смогу понять, лишь проанализировав правильный код. Не зачти за лишний труд. Плиз!
Установка признака таймсерии делается один раз, а не на каждом тике. И не для одного буфера, а для всех. Поэтому и проблема:
OsMA_Handle=iOsMA(NULL,PERIOD_CURRENT,FastEMA,SlowEMA,SignalSMA,applied_price); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Функция деинициализации | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { IndicatorRelease(OsMA_Handle); // удаляет хэндл индикатора и освобождает память занимаемую им ArrayFree(Up_OsMA_Buffer); // освобождаем динамический массив от данных ArrayFree(Dn_OsMA_Buffer); ArrayFree(OsMA_Buffer); } //==================================================================== //+------------------------------------------------------------------+ //| 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[]) { int calculated = BarsCalculated(OsMA_Handle); if(calculated < rates_total) { Alert("Not all data of OsMA_Handle is calculated (", calculated, "bars ). Error", GetLastError()); return(0); }
//--- we can copy not all data int to_copy; if(prev_calculated>rates_total || prev_calculated<0) to_copy = rates_total; else { to_copy = rates_total-prev_calculated; to_copy++; } //--- get OsMA_Buffer buffer if(CopyBuffer(OsMA_Handle, 0, 0, to_copy, OsMA_Buffer)<=0) { Print("Getting OsMA_Buffer is failed! Error", GetLastError()); return(0); }
//--- int k,limit; if(prev_calculated == 0) limit = rates_total - 2; else limit = fmin(rates_total - prev_calculated, rates_total - 2); //--- the main loop of calculations for(k = limit; k >= 0; --k) { Dn_OsMA_Buffer[k] = 0.0; Up_OsMA_Buffer[k] = 0.0;
Установка признака таймсерии делается один раз, а не на каждом тике. И не для одного буфера, а для всех. Поэтому и проблема:
Все точно! В этом проблема. А что с советниками? Вот пример на сайте mql5.com /---- indicator buffers double MA[]; // массив для индикатора iMA //---- handles for indicators int MA_handle; // указатель на индикатор iMA //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- создание указателя на объект - индикатор iMA MA_handle=iMA(NULL,0,21,0,MODE_EMA,PRICE_CLOSE); return(0); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- заполнение массива MA[] текущими значениями индикатора iMA //--- в массив будет записано 100 элементов CopyBuffer(MA_handle,0,0,100,MA); //--- задаём порядок индексации массива MA[] как в MQL4 ArraySetAsSeries(MA,true); //--- а дальше делайте с этими данными всё что угодно, например: if(MA[0]>MA[1]) { //--- выполнение каких-то операций } }
1. Почему в советниках порядок индексации делается на каждом тике? 2. Есть ли возможность в советниках обновлять последние бары как в индикаторах, если для анализа нужно большое их количество. 3. И стоит ли использовать динамический массив, если для анализа брать 2 последних бара.
Можно ли написать так:
double MA[2]; // массив для индикатора iMA //---- handles for indicators int MA_handle; // указатель на индикатор iMA //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- создание указателя на объект - индикатор iMA MA_handle=iMA(NULL,0,21,0,MODE_EMA,PRICE_CLOSE); //--- задаём порядок индексации массива MA[] как в MQL4 ArraySetAsSeries(MA,true); return(0); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- заполнение массива MA[] текущими значениями индикатора iMA //--- в массив будет записано 2 элементов CopyBuffer(MA_handle,0,0,2,MA);
//--- а дальше делайте с этими данными всё что угодно, например: if(MA[0]>MA[1]) { //--- выполнение каких-то операций } }
Статический массив нельзя сделать таймсерией. Но ничего страшного в динамических массивах нет. Ведь функция CopyBuffer сама перераспределит память под массив при первом вызове. При последующих вызовах на это не будет уходить время. Поэтому вполне можно сделать так, проверяя попутно формирование нового бара:
Отправлено: 18.02.18 09:47. Заголовок: Столкнулся с не пони..
Столкнулся с не пониманием обращения к функции... в mql4. //+------------------------------------------------------------------+ //| Проверяет объем ордера на корректность | //+------------------------------------------------------------------+ bool CheckVolumeValueStart(double volume,string &description) { //--- минимально допустимый объем для торговых операций double min_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MIN); if(volume<min_volume) { description=StringFormat("Объем меньше минимально допустимого SYMBOL_VOLUME_MIN=%.2f",min_volume); return(false); }
//--- максимально допустимый объем для торговых операций double max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX); if(volume>max_volume) { description=StringFormat("Объем больше максимально допустимого SYMBOL_VOLUME_MAX=%.2f",max_volume); return(false); }
int ratio=(int)MathRound(volume/volume_step); if(MathAbs(ratio*volume_step-volume)>0.0000001) { description=StringFormat("Объем не является кратным минимальной градации SYMBOL_VOLUME_STEP=%.2f, ближайший корректный объем %.2f", volume_step,ratio*volume_step); return(false); } description="Корректное значение объема"; return(true); } //============================================================================= Что делать с &description? if (!CheckVolumeValueStart(Lot,................)) return; Конечно, можно его убрать из функции, а в тексте заменить на Print. Но хотелось бы разобраться, что это значит и как правильно применить. Спасибо!
Отправлено: 18.02.18 16:55. Заголовок: Sergey пишет: Что д..
Sergey пишет:
цитата:
Что делать с &description? if (!CheckVolumeValueStart(Lot,................)) return; Конечно, можно его убрать из функции, а в тексте заменить на Print. Но хотелось бы разобраться, что это значит и как правильно применить.
Этот аргумент функции нужно рассматривать как сообщение об ошибке. Пользоваться так:
Отправлено: 18.02.18 19:03. Заголовок: Admin пишет: Могу с..
Admin пишет:
цитата:
string description = "";
А вот это я и пропустил. Забыл объявить. Спасибо Игорь! Admin пишет:
цитата:
Могу согласиться с тем, что в качестве примера такой прием вызывает недоумение. Скорее всего взято из какого-то готового проекта и вставлено как есть.
В маркете на mql5.com при валидации (автоматической проверки на наличие ошибок) это выдано в качестве примера. Авто контроль проверяет каждую из позиций: минимальный и максимальный лот, кратность шагу и достаточность свободных средств для стартового лота в советнике. Причем ошибка обязательно должна быть выведена в журнал (Print) иначе проверку сова на проходит. Пришлось сделать отдельную объединенную функцию на будущее. Замучился, пока понял, что ошибка неправильные объемы относятся к стартовому лоту.
Отправлено: 19.02.18 12:12. Заголовок: Сейчас другая пробле..
Сейчас другая проблема:"Необходимо добавить возможность проверки торговых функций программы на наличие ошибок в Тестере стратегий." В советнике заложен вывод (Alert), если ордер не установлен, при условии, что все параметры заданы правильно. Что еще нужно не пойму. Ведь Alert в журнал тоже выводится. Может кто подскажет, что означает выше указанная ошибка..... И вот это: TickValue = MarketInfo(Symbol(), MODE_TICKVALUE); double Lot = CalculatedProfit/TickValue/TakeProfit;
TickValue почему-то именно для золота равно 0. Валютные пары тестирование проходят. Бред какой-то. Как обойти не знаю. В тестере ошибок нет.
Сейчас другая проблема:"Необходимо добавить возможность проверки торговых функций программы на наличие ошибок в Тестере стратегий." В советнике заложен вывод (Alert), если ордер не установлен, при условии, что все параметры заданы правильно. Что еще нужно не пойму. Ведь Alert в журнал тоже выводится. Может кто подскажет, что означает выше указанная ошибка.....
Alert при тестировании выводится в журнал тестера по аналогии с функцией Print. Само окно и звуковой сигнал, конечно же, не отображается ни в одном из режимов тестирования.
Sergey пишет:
цитата:
И вот это: TickValue = MarketInfo(Symbol(), MODE_TICKVALUE); double Lot = CalculatedProfit/TickValue/TakeProfit;
TickValue почему-то именно для золота равно 0. Валютные пары тестирование проходят. Бред какой-то. Как обойти не знаю. В тестере ошибок нет.
Проверил для золота на Альпари. Есть значение. А в онлайн что показывает? Еще можно попробовать заменить на более современную форму:
ще можно попробовать заменить на более современную форму:
За эту подсказку спасибо. Что современнее , то и надо применять. Scriptong пишет:
цитата:
А в онлайн что показывает?
Значения есть. Мне видится дело не в этом, а в настойках стартового лота. Проблему решил так: Установил в стартовых настройках вместо расчетного постоянный лот. Таким образом строка в авто проверку не попала. Теперь жду замечания от модератора.....
Значения есть. Мне видится дело не в этом, а в настойках стартового лота. Проблему решил так: Установил в стартовых настройках вместо расчетного постоянный лот. Таким образом строка в авто проверку не попала. Теперь жду замечания от модератора
Ну это пока Вы решили радикально. Но ведь такая возможность может потребоваться в будущем. Значит, следует разобраться, почему на золоте получены нулевые значения. Кроме того, в том коде, который Вы привели, нет проверки деления на 0. Может просто ввести ее и ждать, пока будет получен не 0? Такое часто бывает при необходимости подкачки данных.
Кроме того, в том коде, который Вы привели, нет проверки деления на 0. Может просто ввести ее и ждать, пока будет получен не 0? Такое часто бывает при необходимости подкачки данных.
Идея верная... Тем более я допустил еще ряд ошибок..... TickValue = MarketInfo(Symbol(), MODE_TICKVALUE); Я закачиваю при инициации в функции OnInit() вместе с другими параметрами, что в принципе не верно, так как для обратных и кросс курсов эта величина не постоянная. Можно дополнить примерно так: в начале OnTick()
TickValue = SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_VALUE); if (TickValue = 0) return;
Верно? Или делать запрос при каждом тике не рационально, а лучше внутри функции расчета лота примерно так:
while (true) { TickValue = SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_VALUE); if (TickValue !=0) break; }
Верно? Или делать запрос при каждом тике не рационально, а лучше внутри функции расчета лота примерно так:
Да, на каждом тике. Ведь рыночное окружение изменяется при изменении цены. Поэтому нужно все данные получать заново. Если какой-то из критически важных параметров (величина пункта, стоимость тика, размер тика и т. п.) равен нулю, то продолжать обработку тика нельзя. Сразу выходить и ждать следующего тика.
Посмотрите, как у меня это реализовано на примере любого советника. Допустим, Quantum. В папке Include\Common есть файл Common_GetSymbolInfo.mqh. В нем - реализация класса GetSymbolInfo. Так вот, метод RefreshInfo этого класса вызывается в начале каждого тика. Внутри этого метода собираются все данные рыночного окружения. При этом неважно, что многие из них (величина пункта, к примеру) практически константы. Всякое может случиться, а потому необходимо быть готовым к изменению любого из этих параметров.
Посмотрите, как у меня это реализовано на примере любого советника.
Огромное спасибо! Я пока сделал так if (!SymbolInfoDouble(Symb, SYMBOL_TRADE_TICK_VALUE,TickValue)) { Comment((isRussianLang)? "Ошибка получения данных SYMBOL_TRADE_TICK_VALUE " : "Error retrieving data SYMBOL_TRADE_TICK_VALUE ",GetLastError()); return; } Но обязательно посмотрю пример. Ваш опыт очень для меня важен. Я именно на ваших примерах научился mql4.
Отправлено: 09.05.18 15:31. Заголовок: Всем Привет! Игорь, ..
Всем Привет! Игорь, подскажи, как определить дыры в истории котировок? Вот пример: индикатор установлен на график Н1, но обсчитывает данные с М1. Последовательность баров без дары 5,4,3,2,1,0 Та же последовательность с дыркой 4,3,_,2,1,0 Проверка типа: //+---------------------------------------------------------------------------+ //| Проверка доступности баров указанного таймфрейма | //+---------------------------------------------------------------------------+ bool IsAllBarsAvailable(int lastBar,int tf) { if(lastBar <= 0) return (false); // Проверка доступности баров for(int i=lastBar; i>=0; i--) if(iTime(Symb,tf,i)==0) return (false); // Все бары доступны return (true); } Эту дырку на М1 не замечает. Почему не пойму.... В результате проверка пройдена, а индикатор на участке с дыркой не рассчитывается. Просьба, если есть готовое решение обнаружения дыр в истории скинь пожалуйста.
Игорь, подскажи, как определить дыры в истории котировок?
К сожалению, не существует универсального способа автоматической проверки наличия дыр в истории. Сам МТ4 довольно часто не замечает их и, соответственно, не заполняет дыры информацией с сервера. В таких случаях рецепт только один: вручную удалять всю историю и закачивать ее заново. Чаще всего помогает.
Почему невозможно создать универсальный алгоритм отслеживания дыр в истории? Да потому что для его создания нужно обладать информацией о том, когда котировки между двумя барами действительно были. То есть нужен эталон, с которым возможно провести сравнение. Но у программы только один источник данных - текущий чарт.
Простой пример. Открываем график и видим, что между 27.04.2018 и 30.04.2018 имеется визуальный разрыв в значениях котировок. Логично предположить, что тут дыра. Но потом смотрим календарь и видим, что это пятница и понедельник соответственно. То есть на самом деле не дыра. Этот случай еще поддается автоматизации. Углубимся. Допустим, последняя свеча минутного графика 27.04.2018 - 22:30, хотя официальное закрытие недели значится как 22:55. Что это: недостаток данных длиной в 25 минут (дыра?) или действительно не было котировок до закрытия, потому что рынок под конец недели вялый? Вот такие случаи невозможно решить без наличия эталона. Только вот если эталон у нас имеется, то и сама проблема автоматически исчезает.
То есть нужен эталон, с которым возможно провести сравнение.
Спасибо. Благодаря твоему разъяснению, возникла идея. Попробую ее изложить и проверить. Суть проблемы: Скажем, Вы не открывали терминал 3 рабочих дня. После открытия терминала на 4 день, данные по всем ТФ обновляются на истории 2048 баров. Для М1 это 1,4 дня, для М5-7,1 дней. Таким образом мы имеем пробел истории котировок только на М1. Теперь, если устроить проверку согласованности графиков для М1 по времени открытия баров старшего тайм-фрейма, мы получим ошибку. Следовательно нужно закачать историю.... Конечно, полностью дыры на М1 таким образом не проверить, но будет понимание в необходимости обновления истории. По крайней мере этого будет достаточно для подбора минимального ТФ с полной закаченной историей. Еще раз спасибо. Бегу реализовывать.....
Отправлено: 12.04.20 19:09. Заголовок: Игорь привет! Хочу а..
Игорь привет! Хочу адаптировать один индикатор для МТ5. К сожалению нет полного понимания как некоторые функции, массивы и т.п. выглядят в mql5. К примеру: Time[5] как будет в mql5.
Все даты в формате GMT
2 час. Хитов сегодня: 0
Права: смайлы да, картинки да, шрифты да, голосования нет
аватары да, автозамена ссылок вкл, премодерация откл, правка нет