Скажите хоть, как вам идея...
Забыл сказать: линию тейк профита можно удалять, если он не нужен.
Тип ордера выбирается в зависимости от расположения опенпрайс и стоплосс..
Что касается личностей ругающих реализацию, то не совсем понятно чем они руководствуются говоря, что реализация "сырая".
Я уверен, что многим будет очень удобно работать с Вашим скриптом для выставления отложенных ордеров.
А для тех, кто любит входить с рынка, я предлагал уже на страницах Forex Magazine (статья "Библиотеки функций и их использование в программах" 52-ой номер за 24 января 2005 года) вариант скрипта, покупающего по текущей рыночной цене с автоматическим посчётом размера лота на основании выставленного стоп лосса. Тогда в MQL4 ещё небыло возможности получить цену, на которой скрипт "опустился" на график, и поэтому цена в нём всегда та, которая на рынке.
Эту же программу можно легко модифицировать, чтобы она открывалась, допустим, одним минилотом с постоянным стопом. А вот этот финт с MessageBox'ом определённо позволит добавить и в мой скрипт функциональности.
//+------------------------------------------------------------------+ //| order_buy.mq4 | //| Copyright c 2004, Alexander Ivanov. | //| mailto:alexander@indus.ru | //+------------------------------------------------------------------+ #property copyright "Copyright c 2004, Alexander Ivanov." #property link "mailto:alexander@indus.ru" #include <WinUser32.mqh> #include <stderror.mqh> // Далее константа DAYS_TO_CONSIDER будет нам заменять количество // дней, на которых мы будем искать минимум для выставления Stop loss'а #define DAYS_TO_CONSIDER 3 ////////////////////////////////////////////////////////////////// // // Необходимо разрешить импорт функций из библиотек. Для этого // нужно поставив галочку 'Разрешить импортирование внешних экспертов' // на закладке 'Советники' окна 'Настройки' вызываемого выбором пункта // меню 'Сервис'->'Настройки' // ////////////////////////////////////////////////////////////////// #include <stdlib.mqh> // содержит нужную нам функцию ErrorDescription(...) int init() { return(0); } int start() { double DaysLowArray[]; int nBarWithMinimum = 0; double dMyStopLoss = 0; double dMyPrice = 0; double dMyTakeProfit = 0; double dMyLots = 0; if(ArrayCopySeries(DaysLowArray, MODE_LOW, Symbol(),PERIOD_D1) < DAYS_TO_CONSIDER) { return(PrintErrorDescription()); } dMyPrice = Ask; dMyStopLoss = DaysLowArray[Lowest(Symbol(),PERIOD_D1,MODE_LOW,DAYS_TO_CONSIDER)]; dMyTakeProfit = dMyPrice + 2*MathMax((MathAbs(Ask-Bid)/2),MathAbs(dMyPrice-dMyStopLoss)); dMyStopLoss -= 10*Point; dMyLots = 0.1; Print("Цена = ", dMyPrice, " Стоп = ", dMyStopLoss, " Тейк профит = ", dMyTakeProfit, " Лот = ", dMyLots); ObjectCreate( "order_buy_Stop_Loss_Line", OBJ_HLINE, 0, 0, dMyStopLoss, 0, 0, 0, 0 ); ObjectSet( "order_buy_Stop_Loss_Line", OBJPROP_COLOR, Red ); ObjectSetText( "order_buy_Stop_Loss_Line", "Stop_Loss_Line", 6, "Arial", Red ); ObjectCreate( "order_buy_Take_Profit_Line", OBJ_HLINE, 0, 0, dMyTakeProfit, 0, 0, 0, 0 ); ObjectSet( "order_buy_Take_Profit_Line", OBJPROP_COLOR, Lime ); ObjectSetText( "order_buy_Take_Profit_Line", "Take_Profit_Line", 6, "Arial", Lime ); int MyError = 0; int Answer = MessageBoxA( 0, "\"order_buy\"\nПереместите линии на необходимые уровни, и нажмите ОК", "Установка ордера", MB_OKCANCEL | MB_ICONASTERISK | MB_TOPMOST); if ( Answer == IDOK ) { dMyStopLoss = ObjectGet( "order_buy_Stop_Loss_Line", OBJPROP_PRICE1); dMyTakeProfit = ObjectGet( "order_buy_Take_Profit_Line", OBJPROP_PRICE1); while(true) { if(OrderSend(Symbol(),OP_BUY,dMyLots,dMyPrice,3,dMyStopLoss,dMyTakeProfit, "Ordered by \"order_buy\" script" ,255,0,HotPink) <= 0) { MyError = PrintErrorDescription(); if((MyError == ERR_NOT_ENOUGH_MONEY) || (MyError == ERR_TRADE_DISABLED) || (MyError == ERR_INVALID_TRADE_PARAMETERS)) { MessageBoxA(0,ErrorDescription(MyError), "Ошибка", MB_OK | MB_ICONERROR); break; } else if(MyError == ERR_INVALID_STOPS) { dMyStopLoss = ObjectGet( "order_buy_Stop_Loss_Line", OBJPROP_PRICE1); dMyTakeProfit = ObjectGet( "order_buy_Take_Profit_Line", OBJPROP_PRICE1); Print("Цена = ", dMyPrice, " Стоп = ", dMyStopLoss, " Тейк профит = ", dMyTakeProfit, " Лот = ", dMyLots); } else if(MyError == ERR_PRICE_CHANGED) { MessageBoxA(0,"Цена успела измениться", "Ошибка", MB_OK | MB_ICONERROR); RefreshRates(); } else { // 10 seconds wait Sleep(10000); } } else { Answer = MessageBoxA( 0, "Ордер успешно исполнен\nРаспечатать ордер?", "Установка ордера", MB_OKCANCEL | MB_ICONASTERISK | MB_TOPMOST); if(Answer == IDOK ) { OrderPrint(); } break; } } } return(MyError); } int PrintErrorDescription() { int error=GetLastError(); Print("Error = ",ErrorDescription(error)); return(error); } int deinit() { ObjectDelete( "order_buy_Stop_Loss_Line"); ObjectDelete( "order_buy_Take_Profit_Line"); return(0); }
У меня как-то неадекватно ведёт себя функция Lowest и ArrayMinimum на графике EURUSD_H1
Дело в том, что судя по всему минимум должен совпасть с последним пятничным значением, но этого не происходит и у меня в качестве минимума возвращается двухдневный минимум.
Код выше, пока график не изменился проверте плиз (т.е. до воскресной ночи).
Может быть я что-то делаю не так?
реализация действительно сырая :) я этот скрипт писАл часа полтора.....
я его предложил как идею, если понравится - необходимо дорабатывать...
Horn 06.02.05 06:45
спасибо за респект ;) а возможностей действительно море - надо искать!
зы: если кто знает, как сделать месседж "поверх всех окон", скажите, плз.... а то так неудубно.....
для автоматизации рутинных операций.
Вот серьезно исправленный и рабочий вариант скрипта для визуальной постановки ордеров:
//+------------------------------------------------------------------+ //| order_buy.mq4 | //| Copyright c 2004, Alexander Ivanov. | //| mailto:alexander@indus.ru | //+------------------------------------------------------------------+ //| Разрешите импорт функций из библиотек через: | //| "Сервис -> Настройки -> Советники -> Разрешить импорт DLL" | //+------------------------------------------------------------------+ #property copyright "Copyright c 2004, Alexander Ivanov." #property link "mailto:alexander@indus.ru" #include <WinUser32.mqh> #include <stdlib.mqh> #include <stderror.mqh> //+------------------------------------------------------------------+ //| Указываем количество последних дней, на которых ищем минимум | //| для установки стоплосса | //+------------------------------------------------------------------+ #define DAYS_TO_CONSIDER 3 //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int init() { return(0); } int deinit() { //---- просто удалим свои линии стопов ObjectDelete( "order_buy_Stop_Loss_Line"); ObjectDelete( "order_buy_Take_Profit_Line"); //---- return(0); } //+------------------------------------------------------------------+ //| Основная функция скрипта | //+------------------------------------------------------------------+ int start() { double DaysLowArray[]; double dMyStopLoss = 0; double dMyPrice = 0; double dMyTakeProfit = 0; double dMyLots = 0; //---- скопируем массив дневных данных if(ArrayCopySeries(DaysLowArray, MODE_LOW, Symbol(),PERIOD_D1) < DAYS_TO_CONSIDER) { return(-1); } //---- расчет цен dMyPrice = Ask; dMyStopLoss = DaysLowArray[Lowest(Symbol(),PERIOD_D1,MODE_LOW,DAYS_TO_CONSIDER,0)]; dMyTakeProfit = dMyPrice + 2*MathMax((MathAbs(Ask-Bid)/2),MathAbs(dMyPrice-dMyStopLoss)); dMyStopLoss -= 10*Point; dMyLots = 0.1; //---- выставим линии для визуального управления стопами ObjectCreate( "order_buy_Stop_Loss_Line", OBJ_HLINE, 0, 0, dMyStopLoss, 0, 0, 0, 0 ); ObjectSet( "order_buy_Stop_Loss_Line", OBJPROP_COLOR, Red ); ObjectSetText( "order_buy_Stop_Loss_Line", "Stop_Loss_Line", 6, "Arial", Red ); ObjectCreate( "order_buy_Take_Profit_Line", OBJ_HLINE, 0, 0, dMyTakeProfit, 0, 0, 0, 0 ); ObjectSet( "order_buy_Take_Profit_Line", OBJPROP_COLOR, Lime ); ObjectSetText( "order_buy_Take_Profit_Line", "Take_Profit_Line", 6, "Arial", Lime ); //---- запросим подтверждение на отработку string quest="Вы хотите купить "+DoubleToStr(dMyLots,2)+" "+Symbol()+" по цене Ask "+ DoubleToStr(dMyPrice,Digits)+" \n\n"+ "Переместите выставленные линии на необходимые уровни и нажмите ОК \n"+ "(красная линия - Stop Loss, зеленая - Take Profit)\n\n"+ "Нажмите Отмена чтобы отказаться от сделки"; if(MessageBoxA(0,quest,"Визуальная установка ордера на покупку", MB_OKCANCEL | MB_ICONASTERISK | MB_TOPMOST)!=IDOK) return(-2); //---- трейдер согласился, возьмем новые уровни стопов и обязательно проверим их! dMyStopLoss =NormalizeDouble(ObjectGet( "order_buy_Stop_Loss_Line", OBJPROP_PRICE1),Digits); dMyTakeProfit=NormalizeDouble(ObjectGet( "order_buy_Take_Profit_Line",OBJPROP_PRICE1),Digits); if((dMyStopLoss>0 && dMyStopLoss>Ask) || (dMyTakeProfit>0 && dMyTakeProfit<Ask)) { Print("Неправильно выставлены уровни Stop Loss и Take Profit!"); MessageBoxA(0,"Неправильно выставлены уровни Stop Loss и Take Profit! \n"+ "Операция отменена\n\n", "Визуальная установка ордера на покупку",MB_OK | MB_ICONSTOP | MB_TOPMOST); return(-3); } //---- выведем в лог сообщение об заявке Print("buy ",DoubleToStr(dMyLots,2)," ",Symbol()," at ",DoubleToStr(dMyPrice,Digits), "sl ",DoubleToStr(dMyStopLoss,Digits)," tp ",DoubleToStr(dMyTakeProfit,Digits)); //---- пробуем послать команду int ticket=OrderSend(Symbol(),OP_BUY,dMyLots,dMyPrice,3,dMyStopLoss,dMyTakeProfit, "Ordered by \"order_buy\" script" ,255,0,HotPink); if(ticket>0) // все отлично - заявка прошла { //---- сразу же выведем в лог подтверждение Print("#",ticket," buy ",DoubleToStr(dMyLots,2)," ",Symbol()," at ", DoubleToStr(dMyPrice,Digits)," is done"); //---- покажем окно if(MessageBoxA(0,"Ордер успешно исполнен \nРаспечатать его?", "Визуальная установка ордера на покупку", MB_YESNO | MB_ICONASTERISK | MB_TOPMOST)==IDYES) { OrderPrint(); } //---- все ок, выходим return(0); } //---- тут все плохо - выведем в лог сообщение int err=GetLastError(); Print("buy ",DoubleToStr(dMyLots,2)," ",Symbol()," at ", DoubleToStr(dMyPrice,Digits)," failed [",ErrorDescription(err),"]"); //----покажем окно MessageBoxA(0,ErrorDescription(err), "Ошибка визуальной установки ордера", MB_OK | MB_ICONERROR | MB_TOPMOST); return(-4); } //+------------------------------------------------------------------+
Что исправлено:
1) указаны все параметры в Lowest(Symbol(),PERIOD_D1,MODE_LOW,DAYS_TO_CONSIDER,0),
похоже что ошибка у Horn'а была в том, что значение по умолчанию не стояло. мы проверим вызов и работу функции Lowest
2) нормализация используемых цен через NormalizeDouble - это очень важно!
3) предварительные проверки уровней стопов на корректность перед отправкой на заявки
4) трейдеру дается больше информации в окнах (в первом варианте скрипта без чтения кода было очень сложно понять - что же делает этот скрипт)
5) детальный и своевременный вывод логов
6) добавлены комментарии
7) убрана цикличная попытка отсылки заявки - это очень важно.
К сожалению, использование зацикленных алгоритмов вида :
while(true) { if(OrderSend(....)<=0) { // проверимся Sleep(10000); } }
абсолютно противопоказано, даже запрещено.
Постараюсь грубо объяснить причину:
Если вы словили ошибку, то все равно не обработаете все типы ошибок самостоятельно. Слишком велика вероятность, что вы отловите штук пять популярных ошибок, что-то для них сделаете, но все равно _для всех остальных_ ошибок будете повторять операции. И никакие Sleep(10000) не будут служить отмазкой того, что скрипт шлет неверные запросы. Брокеры просто счет заблокируют.
Как надо действовать писателю экспертов:
1) этап подготовки заявки
а) проверить входные параметры эксперта на корректность
б) самостоятельно нормализовать все цены и объемы(да, их тоже!) заявки
в) самостоятельно проверить все поля заявки на глупейшие ошибки, как минимум - чтобы все цены были более-менее корректны
г) перед отсылкой заявки вывести детали заявки в лог
2) организация цикла посылки заявки
а) цикл должен быть конечным, например не более 3х раз for(i=0;i<3;i++) и ни в коем случае не while(true)
б) если заявка прошла, то все легко: выводим в лог, уведомляем трейдера и выходим
в) словили ошибку, то пункт 3
3) обработка ошибок отсылки заявок
а) проверяем те ситуации, в которых мы можем восстановиться, а при любой другой ошибке - выходим с уведомлениями как можно скорее
б) случаев восстановления выбираем как можно меньше, только самые главные и потенциально восстановимые
в) никаких попыток "проталкивания" своей повторной заявки с мыслью "может все-таки примут?"
г) обязательный учет слиппажа, как минимум 1 пункт (будьте честны с собой, слиппаж неизбежен в реальной торговле)
Одним из главных моментов в использовании исполнения заявок из MQL4 - минимизируйте количество заявок.
Это напрямую влияет на качество вашего обслуживания.
Также для экспертов, пишущихся на публику, необходимо писать максимально защищенный дуракоустойчивый код.
Да и для внутреннего использования - тоже.
я использовал MB_TOPMOST, попробуй, у меня вроде бы получилось.
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Вчера вот вспомнил, подумал - а почему бы не реализовать?
редакция от 19.03.2005г
Перед использованием прочитайте инструкцию =)
Если у кого какие идеи - говорите, будем думать.
Может, своими силами сделаем ГУО.........;)