//+------------------------------------------------------------------+ //| ZiCo_v1.1.mq4 | //| AriusKis | //| AriusKis@gmail.com | //| К базовой версии добавлен перевод в безубыток, добавлены верхние | //|границы коррекций (ограничение), минимальный стоп-лосс | //+------------------------------------------------------------------+ #property copyright "AriusKis" #property link "AriusKis@gmail.com" #property version "1.1" #property strict enum howstop { lastcorrection=0, //по коррекции main_swing=1 //по основному свингу }; struct ZigZagData { double point_1; //первая точка справа double point_2; //вторая точка справа double point_3; //третья точка справа double mainsize; //размер последнего свинга bool upward; //последний свинг: false - нисходящий, true - восходящий bool swingOK; //подходит свинг или нет }; struct orderdata { double BEprice; //цена для перевода в безубыток double SLvalue; //размер стоп-лосса int ticket; //тикет ордера bool alreadyBE; //переведен ли в безубыток }; enum yesorno { no=0, //нет yes=1 //да }; input string Head = " AriusKis@gmail.com |----- "; // -----| Created by AriusKis, email - input string ZigZagSettings = " индикатора ZigZag |----- "; // -----| Входные настройки input int InpDepth = 12; input int InpDeviation = 5; input int InpBackstep = 3; input string Settings4Entry = " для входа |----- "; // -----| Настройки input int VolatDays = 20; //Количество дней для расчета волатильности input double K_volat = 0.5; //Коэффициент вол-ти для миним. свинга input double Minswing = 200; //Минимальный свинг в пунктах input double Correctionmin = 50; //% коррекции для разворота минимальный input double Correctionmax = 100; //% коррекции для разворота максимальный input double EntryCorrmin = 30; //% коррекции для входа минимальный input double EntryCorrmax = 50; //% коррекции для входа максимальный input string Formonitor = " сделкой |----- "; // -----| Настройки управления input howstop SLmode = 0; //Где выставлять стоп-лосс input double SLmin = 50; //Минимальный стоп-лосс в пунктах input int Indent = 20; //Отступ от экстр. для SL в пунктах input double K_TP = 2; //Отношение тейка к стопу input yesorno SwitchBE = 0; //Использовать перевод в безубыток? input double K_BE = 1; //Коэффициент от стоп-лосса для перевода в б/у input string AdditionalSet = " настройки |----- "; // -----| Дополнительные input double Risk = 1; //Риск на сделку, % от депо input int Slippage = 30; input int Magic = 222; datetime opentime=0; ZigZagData ZZD = {0,0,0,0,false, false}; bool first_condition=false; int orderdir = -1; double maincorrection; orderdata sellOD = {0,0,0,false}; orderdata buyOD = {0,0,0,false}; double memoryprice; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { if(InpDepth<=0 || InpBackstep<=0 || InpDeviation<=0) { Alert("Входные параметры для ZigZag должны быть больше нуля!"); return(INIT_FAILED); } if(VolatDays<2) { Alert("Количество дней для расчета волатильности должно быть больше одного!"); return(INIT_FAILED); } if(K_volat<0 || Minswing<0 || Correctionmin<0 || Correctionmax<0 || EntryCorrmin<0 || EntryCorrmax<0) { Alert("Все настройки для входа не могут быть ниже нуля!"); return(INIT_FAILED); } if(Correctionmin>=Correctionmax || EntryCorrmin>=EntryCorrmax) { Alert("Неверно выставлены % коррекций! Минимальные должны быть больше максимальных!"); return(INIT_FAILED); } if(K_TP<=0 || Slippage<=0 || Magic<=0) { Alert("Дополнительные настройки - отношение тейка к стопу, Slippage и Magic должны быть больше нуля!"); return(INIT_FAILED); } return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { if(Time[0]!=opentime) { FillZigZagData(); if(ZZD.swingOK) first_condition = CheckSignal(); else first_condition = false; if(ZZD.point_1==memoryprice) first_condition = false; //Ждем обновления экстремума зиг-зага opentime=Time[0]; } if(first_condition) Monitor4entry(); if(SwitchBE==1) MonitorBE(); } //+------------------------------------------------------------------+ //| Проверяем триггер для перевода в безубыток и переводим | //+------------------------------------------------------------------+ void MonitorBE() { bool modanswer = false; if(!buyOD.alreadyBE && CountOrders(0)>0) //Проверка ордера на покупку { if(Bid>=buyOD.BEprice && OrderSelect(buyOD.ticket,SELECT_BY_TICKET,MODE_TRADES)) { if(IsTesting()) modanswer = OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice(),OrderTakeProfit(),0,clrNONE); else modanswer = OrderModifyx(OrderTicket(),OrderOpenPrice(),OrderOpenPrice(),OrderTakeProfit(),0,clrNONE); } if(modanswer) buyOD.alreadyBE = true; } modanswer = false; if(!sellOD.alreadyBE && CountOrders(1)>0) //Проверка ордера на продажу { if(Ask<=sellOD.BEprice && OrderSelect(sellOD.ticket,SELECT_BY_TICKET,MODE_TRADES)) { if(IsTesting()) modanswer = OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice(),OrderTakeProfit(),0,clrNONE); else modanswer = OrderModifyx(OrderTicket(),OrderOpenPrice(),OrderOpenPrice(),OrderTakeProfit(),0,clrNONE); } if(modanswer) sellOD.alreadyBE = true; } } //+------------------------------------------------------------------+ //| Проверяем наличие второго сигнала и входим | //+------------------------------------------------------------------+ void Monitor4entry() { double corrnow = (MathAbs(ZZD.point_1-Bid))/maincorrection; if(orderdir==0) { if(CountOrders(0)>0) //сразу стопорим, если уже есть ордера return; if(corrnow >= EntryCorrmin/100 && corrnow <= EntryCorrmax/100) //Второе условие для входа DealOpen(orderdir); } else { if(CountOrders(1)>0) return; if(corrnow >= EntryCorrmin/100 && corrnow <= EntryCorrmax/100) DealOpen(orderdir); } } //+------------------------------------------------------------------+ //| Находим все параметры и входим в рынок | //+------------------------------------------------------------------+ void DealOpen(int typeorder) { double TP,SL,LOT,price,slvalue; int Ticket; color col; if(typeorder==0) { price=Ask; if(SLmode==0) SL = ZZD.point_1-Indent*_Point; else SL = ZZD.point_3-Indent*_Point; slvalue = Ask - SL; TP = Ask + K_TP*slvalue; col = clrBlue; } else { price = Bid; if(SLmode==0) SL = ZZD.point_1+Indent*_Point; else SL = ZZD.point_3+Indent*_Point; slvalue = SL - Bid; TP = Bid - K_TP*slvalue; col = clrRed; } if(slvalue/_Point0) { if(typeorder==0) { buyOD.ticket = Ticket; buyOD.alreadyBE = false; buyOD.SLvalue = slvalue; buyOD.BEprice = price + K_BE*slvalue; } if(typeorder==1) { sellOD.ticket = Ticket; sellOD.alreadyBE = false; sellOD.SLvalue = slvalue; sellOD.BEprice = price - K_BE*slvalue; } } } //+---------------------------------------------------------------------+ //| Функция вычисления объема сделки - здесь от еквити и проверяется шаг| //+---------------------------------------------------------------------+ double DealVolume(double riskcount,double sl) { double lot_min = MarketInfo(_Symbol, MODE_MINLOT); double lot_max = MarketInfo(_Symbol, MODE_MAXLOT); double lot_step = MarketInfo(_Symbol, MODE_LOTSTEP); double lotcost = MarketInfo(_Symbol, MODE_TICKVALUE); double lot=0; double UsdPerPip=0; lot = MathMin(AccountBalance(), AccountEquity())*riskcount/100; UsdPerPip=lot/sl; lot=UsdPerPip/lotcost; lot = MathFloor(lot/lot_step)*lot_step; if(lotlot_max) lot = lot_max; return(lot); } //+------------------------------------------------------------------+ //| Находим открытые ордера советника и их число | //+------------------------------------------------------------------+ int CountOrders(int ord_type) { int i; int ordcount=0; for(i=OrdersTotal()-1; i>=0; i--) { if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)) { if(OrderSymbol()==_Symbol && OrderMagicNumber()==Magic) { if(OrderType()==ord_type) ordcount++; } } } return(ordcount); } //+------------------------------------------------------------------+ //| Проверяем наличие сигнала для старта мониторинга | //+------------------------------------------------------------------+ bool CheckSignal() { double correctionnow; if(ZZD.upward) //если свинг 3-2 направлен вверх { if(ZZD.point_1>ZZD.point_3) { maincorrection = ZZD.point_2-ZZD.point_1; correctionnow = maincorrection/ZZD.mainsize; if(correctionnow >= Correctionmin/100 && correctionnow <= Correctionmax/100) //Основное условие - коррекция стала больше требуемой { first_condition = true; orderdir = 0; //будем искать точку для входа на покупки return(true); } } } else { if(ZZD.point_1= Correctionmin/100 && correctionnow <= Correctionmax/100) { first_condition = true; orderdir = 1; //ищем продажи return(true); } } } return(false); } //+------------------------------------------------------------------+ //| Заполняем последние данные по ZigZag | //+------------------------------------------------------------------+ void FillZigZagData() { int i; double ZZvalue; int step = 0; double minpips=0; for(i=1; i<=1000; i++) { ZZvalue = iCustom(_Symbol,0,"ZigZag",InpDepth,InpDeviation,InpBackstep,0,i); if(ZZvalue!=0) { if(step==2) { ZZD.point_3 = ZZvalue; break; } if(step==1) { if(ZZvalue!=ZZD.point_2) { ZZD.point_2 = ZZvalue; step=2; } else break; } if(step==0) { if(ZZvalue!=ZZD.point_1) { ZZD.point_1 = ZZvalue; step=1; } else break; } } } if(ZZD.point_2>ZZD.point_3) { ZZD.upward=true; ZZD.mainsize = ZZD.point_2-ZZD.point_3; } else { ZZD.upward=false; ZZD.mainsize = ZZD.point_3-ZZD.point_2; } //Сразу проверим величину свинга на соответствие минимальному значению minpips = K_volat*Volatility(VolatDays); if(Minswing>minpips/_Point) minpips = Minswing*_Point; if(ZZD.mainsize>=minpips) ZZD.swingOK = true; else ZZD.swingOK = false; } //+--------------------------------------------------------------------------+ //| Функция расчета волатильности по заданному количеству дневных баров | //+--------------------------------------------------------------------------+ double Volatility(int period) { double Differ[]; ArrayResize(Differ,period+1,1); double diff1, diff=0; int i, count=0; for(i=1; i<=period; i++) //Заполнение массива Differ[i]=iHigh(_Symbol,PERIOD_D1,i)-iLow(_Symbol,PERIOD_D1,i); //Рассчитываем величину дневных свечей for(i=1; i<=period; i++) { diff+=Differ[i]; count++; } diff1=diff/count; //Показатель волатильности без учета текущего бара return(diff1); } //+------------------------------------------------------------------+ //| Функция-обработчик ошибок при открытии ордеров | //+------------------------------------------------------------------+ int OrderSendx(string symbolx, int cmdx, double volumex, double pricex, int slippagex, double stoplossx, double takeprofitx, string commentx, int magicx, datetime expirationx, color arrow_colorx) { int err = 0; bool exit_loop = false; int ticketx = -1; int Retry = 10; int cnt = 0; while (!exit_loop) { ticketx = OrderSend(symbolx, cmdx, volumex, pricex, slippagex, stoplossx, takeprofitx, commentx, magicx, expirationx, arrow_colorx); err = GetLastError(); switch(err) { case ERR_NO_ERROR: exit_loop = true; return(ticketx); case ERR_SERVER_BUSY: case ERR_NO_CONNECTION: case ERR_INVALID_PRICE: case ERR_TRADE_TIMEOUT: case ERR_OFF_QUOTES: case ERR_BROKER_BUSY: case ERR_TRADE_CONTEXT_BUSY: cnt++; break; case ERR_PRICE_CHANGED: case ERR_REQUOTE: RefreshRates(); cnt++; continue; default: exit_loop = true; break; } if (cnt>Retry) { exit_loop = true; Print("Ошибка открытия ордера после ", cnt, " попыток"); } if (err != ERR_NO_ERROR) Print("Ошибка открытия ордера - ", ErrorDescription(err)); //Вместо err добавить функцию из включаемого файла ErrorDescription(err) if (!exit_loop) { Sleep(3000); RefreshRates(); if (cmdx==OP_SELL) pricex=Bid; if (cmdx==OP_BUY) pricex=Ask; } } return(ticketx); } //+------------------------------------------------------------------+ //| Описание ошибок на русском | //+------------------------------------------------------------------+ string ErrorDescription(int error) { string ErrorNumber; switch(error) { case 0: case 1: ErrorNumber = "Нет ошибки, но результат неизвестен"; break; case 2: ErrorNumber = "Общая ошибка"; break; case 3: ErrorNumber = "Неправильные параметры"; break; case 4: ErrorNumber = "Торговый сервер занят"; break; case 5: ErrorNumber = "Старая версия клиентского терминала"; break; case 6: ErrorNumber = "Нет связи с торговым сервером"; break; case 7: ErrorNumber = "Недостаточно прав"; break; case 8: ErrorNumber = "Слишком частые запросы"; break; case 9: ErrorNumber = "Недопустимая операция нарушающая функционирование сервера"; break; case 64: ErrorNumber = "Счет заблокирован"; break; case 65: ErrorNumber = "Неправильный номер счета"; break; case 128: ErrorNumber = "Истек срок ожидания совершения сделки"; break; case 129: ErrorNumber = "Неправильная цена"; break; case 130: ErrorNumber = "Неправильные стопы"; break; case 131: ErrorNumber = "Неправильный объем"; break; case 132: ErrorNumber = "Рынок закрыт"; break; case 133: ErrorNumber = "Торговля запрещена"; break; case 134: ErrorNumber = "Недостаточно денег для совершения операции"; break; case 135: ErrorNumber = "Цена изменилась"; break; case 136: ErrorNumber = "Нет цен"; break; case 137: ErrorNumber = "Брокер занят"; break; case 138: ErrorNumber = "Новые цены - Реквот"; break; case 139: ErrorNumber = "Ордер заблокирован и уже обрабатывается"; break; case 140: ErrorNumber = "Разрешена только покупка"; break; case 141: ErrorNumber = "Слишком много запросов"; break; case 145: ErrorNumber = "Модификация запрещена, так как ордер слишком близок к рынку";break; case 146: ErrorNumber = "Подсистема торговли занята"; break; case 147: ErrorNumber = "Использование даты истечения ордера запрещено брокером"; break; case 148: ErrorNumber = "Количество открытых и отложенных ордеров достигло предела "; break; case 149: ErrorNumber = "Запрещено хэджирование"; break; case 150: ErrorNumber = "Запрещено правилами FIFO"; break; case 4000: ErrorNumber = "Нет ошибки"; break; case 4001: ErrorNumber = "Неправильный указатель функции"; break; case 4002: ErrorNumber = "Индекс массива - вне диапазона"; break; case 4003: ErrorNumber = "Нет памяти для стека функций"; break; case 4004: ErrorNumber = "Переполнение стека после рекурсивного вызова"; break; case 4005: ErrorNumber = "На стеке нет памяти для передачи параметров"; break; case 4006: ErrorNumber = "Нет памяти для строкового параметра"; break; case 4007: ErrorNumber = "Нет памяти для временной строки"; break; case 4008: ErrorNumber = "Неинициализированная строка"; break; case 4009: ErrorNumber = "Неинициализированная строка в массиве"; break; case 4010: ErrorNumber = "Нет памяти для строкового массива"; break; case 4011: ErrorNumber = "Слишком длинная строка"; break; case 4012: ErrorNumber = "Остаток от деления на ноль"; break; case 4013: ErrorNumber = "Деление на ноль"; break; case 4014: ErrorNumber = "Неизвестная команда"; break; case 4015: ErrorNumber = "Неправильный переход"; break; case 4016: ErrorNumber = "Неинициализированный массив"; break; case 4017: ErrorNumber = "Вызовы DLL не разрешены"; break; case 4018: ErrorNumber = "Невозможно загрузить библиотеку"; break; case 4019: ErrorNumber = "Невозможно вызвать функцию"; break; case 4020: ErrorNumber = "Вызовы внешних библиотечных функций не разрешены"; break; case 4021: ErrorNumber = "Недостаточно памяти для строки, возвращаемой из функции"; break; case 4022: ErrorNumber = "Система занята"; break; case 4050: ErrorNumber = "Неправильное количество параметров функции"; break; case 4051: ErrorNumber = "Недопустимое значение параметра функции"; break; case 4052: ErrorNumber = "Внутренняя ошибка строковой функции"; break; case 4053: ErrorNumber = "Ошибка массива"; break; case 4054: ErrorNumber = "Неправильное использование массива-таймсерии"; break; case 4055: ErrorNumber = "Ошибка пользовательского индикатора"; break; case 4056: ErrorNumber = "Массивы несовместимы"; break; case 4057: ErrorNumber = "Ошибка обработки глобальныех переменных"; break; case 4058: ErrorNumber = "Глобальная переменная не обнаружена"; break; case 4059: ErrorNumber = "Функция не разрешена в тестовом режиме"; break; case 4060: ErrorNumber = "Функция не подтверждена"; break; case 4061: ErrorNumber = "Ошибка отправки почты"; break; case 4062: ErrorNumber = "Ожидается параметр типа string"; break; case 4063: ErrorNumber = "Ожидается параметр типа integer"; break; case 4064: ErrorNumber = "Ожидается параметр типа double"; break; case 4065: ErrorNumber = "В качестве параметра ожидается массив"; break; case 4066: ErrorNumber = "Запрошенные исторические данные в состоянии обновления"; break; case 4067: ErrorNumber = "Ошибка при выполнении торговой операции"; break; case 4099: ErrorNumber = "Конец файла"; break; case 4100: ErrorNumber = "Ошибка при работе с файлом"; break; case 4101: ErrorNumber = "Неправильное имя файла"; break; case 4102: ErrorNumber = "Слишком много открытых файлов"; break; case 4103: ErrorNumber = "Невозможно открыть файл"; break; case 4104: ErrorNumber = "Несовместимый режим доступа к файлу"; break; case 4105: ErrorNumber = "Ни один ордер не выбран"; break; case 4106: ErrorNumber = "Неизвестный символ"; break; case 4107: ErrorNumber = "Неправильный параметр цены для торговой функции"; break; case 4108: ErrorNumber = "Неверный номер тикета"; break; case 4109: ErrorNumber = "Торговля не разрешена"; break; case 4110: ErrorNumber = "Длинные позиции не разрешены"; break; case 4111: ErrorNumber = "Короткие позиции не разрешены"; break; case 4200: ErrorNumber = "Объект уже существует"; break; case 4201: ErrorNumber = "Запрошено неизвестное свойство объекта"; break; case 4202: ErrorNumber = "Объект не существует"; break; case 4203: ErrorNumber = "Неизвестный тип объекта"; break; case 4204: ErrorNumber = "Нет имени объекта"; break; case 4205: ErrorNumber = "Ошибка координат объекта"; break; case 4206: ErrorNumber = "Не найдено указанное подокно"; break; case 4207: ErrorNumber = "Ошибка при работе с объектом"; break; case 4210: ErrorNumber = "Неверные свойства графика"; break; case 4211: ErrorNumber = "График не найдено"; break; case 4212: ErrorNumber = "Подокно не найдено"; break; case 4213: ErrorNumber = "Индикатор на графике не найден"; break; case 4220: ErrorNumber = "Ошибка выбора валютной пары"; break; case 4250: ErrorNumber = "Ошибка отправки Push-уведомления"; break; case 4251: ErrorNumber = "Ошибка параметров Push-уведомления"; break; case 4252: ErrorNumber = "Push-уведомления отключены"; break; case 4253: ErrorNumber = "Слишком частые отправки Push-уведомлений"; break; case 4260: ErrorNumber = "ftp-сервер неверный"; break; case 4261: ErrorNumber = "ftp-логин нуверный"; break; case 4262: ErrorNumber = "ftp соединение не удалось"; break; case 4263: ErrorNumber = "ftp соединение закрыто"; break; case 4264: ErrorNumber = "Ошибка смены ftp-пути"; break; case 4265: ErrorNumber = "Ошибка ftp-файла"; break; case 4266: ErrorNumber = "Общая ошибка ftp"; break; case 5001: ErrorNumber = "Слишком много открытых файлов"; break; case 5002: ErrorNumber = "Неверное имя файла"; break; case 5003: ErrorNumber = "Слишком длинное имя файла"; break; case 5004: ErrorNumber = "Невозможно открыть файл"; break; case 5005: ErrorNumber = "Ошибка распределения текста в буфере файла"; break; case 5006: ErrorNumber = "Невозможно удалить файл"; break; case 5007: ErrorNumber = "Неверный индекс файла (закрыт или не был открыт)"; break; case 5008: ErrorNumber = "Неверный индекс файла (индекс вне списка системы)"; break; case 5009: ErrorNumber = "Файл должен быть открыт с флагом FILE_WRITE"; break; case 5010: ErrorNumber = "Файл должен быть открыт с флагом FILE_READ"; break; case 5011: ErrorNumber = "Файл должен быть открыт с флагом FILE_BIN"; break; case 5012: ErrorNumber = "Файл должен быть открыт с флагом FILE_TXT"; break; case 5013: ErrorNumber = "Файл должен быть открыт с флагом FILE_TXT или FILE_CSV"; break; case 5014: ErrorNumber = "Файл должен быть открыт с флагом FILE_CSV"; break; case 5015: ErrorNumber = "Ошибка чтения файла"; break; case 5016: ErrorNumber = "Ошибка записи файла"; break; case 5017: ErrorNumber = "Размер строки должен быть адаптирован для бинарных файлов"; break; case 5018: ErrorNumber = "Несовместимый файл (для строковых мас-TXT, для других-BIN)"; break; case 5019: ErrorNumber = "Файл является каталогом, а не файлом"; break; case 5020: ErrorNumber = "Файл не существует"; break; case 5021: ErrorNumber = "Файл не может быть перезаписан"; break; case 5022: ErrorNumber = "Неверное имя каталога"; break; case 5023: ErrorNumber = "Каталог не существует"; break; case 5024: ErrorNumber = "Определенный файл не каталог"; break; case 5025: ErrorNumber = "Невозможно удалить каталог"; break; case 5026: ErrorNumber = "Невозможно очистить каталог"; break; case 5027: ErrorNumber = "Ошибка изменения размера массива"; break; case 5028: ErrorNumber = "Ошибка изменения размера строки"; break; case 5029: ErrorNumber = "Структура содержит строки или динамические массивы"; break; default: ErrorNumber = "Неизвестная ошибка"; } return (ErrorNumber); } //+------------------------------------------------------------------+ //| Функция-обработчик ошибок при модификации ордеров | //+------------------------------------------------------------------+ bool OrderModifyx(int ticketx, double pricex, double stoplossx, double takeprofitx, datetime expirationx, color arrow_colorx) { int err = 0; bool exit_loop = false; bool answer = false; int Retry = 10; int cnt = 0; while (!exit_loop) { answer = OrderModify(ticketx, pricex, stoplossx, takeprofitx, expirationx, arrow_colorx); err = GetLastError(); switch(err) { case ERR_NO_ERROR: exit_loop = true; return(answer); case ERR_SERVER_BUSY: case ERR_NO_CONNECTION: case ERR_INVALID_PRICE: case ERR_TRADE_TIMEOUT: case ERR_OFF_QUOTES: case ERR_BROKER_BUSY: case ERR_TRADE_CONTEXT_BUSY: cnt++; break; default: exit_loop = true; break; } if (cnt>Retry) { exit_loop = true; Print("Ошибка модификации ордера после ", cnt, " попыток"); } if (err != ERR_NO_ERROR) Print("Ошибка модификации ордера - ", err); //Вместо err добавить функцию из включаемого файла ErrorDescription(err) if (!exit_loop) { Sleep(5000); RefreshRates(); } } return(answer); } //+------------------------------------------------------------------+