//+-------------------------------------------------------------------------------------+ //| AMKAandWilder_Expert.mq4 | //| Scriptong | //| | //+-------------------------------------------------------------------------------------+ #property copyright "Scriptong" #property link "scriptong@mail.ru" //---- input parameters extern double Lots = 0.1; // Объем открываемой позиции extern int TakeProfit = 2000; extern int StopLoss = 2000; extern double TPKoef = 0.9; extern double SLKoef = 1.1; extern int ResultsPeriod = 11; extern string A3 = "Параметры индикатора AMKA"; extern int AMKAPeriod=9; // Период AMKA extern int FastEMAPeriod=2; // Период быстрой скользящей для AMKA extern int SlowEMAPeriod=30; // Период быстрой скользящей для AMKA extern double PowLevel=2.0; // Степень, в которую возводятся составляющие AMKA // 2 - среднеквадратичное значение, // 3 - среднекубическое и т. д. extern double dK = 1.0; // коэффициент для фильтра extern bool UseStdDev = True; // использовать ли среднеквадратичное отклонение? extern int AMKAPrice = 5; // Цена расчета AMKA (0 - 6) extern string A4 = "====================================="; extern string OpenOrderSound = "ok.wav"; // Звук для открытия позиции extern int MagicNumber = 17589 ; // Магик позиций советника bool Activate, FreeMarginAlert, FatalError; double Tick, Spread, StopLevel, MinLot, MaxLot, LotStep, CurRed, CurBlue; datetime LastBar; int TypeOrder, LastType, TicketOrder, Signal; // Переменные для самотеста int Trade = -1, //Текущая сделка (-1 - нет, 0 - BUY, 1 - SELL) ProfitSeries = 0, // количество профитных сделок подряд EqualProfits = 0, // Общее количество прибыльных сделок CountProfits = 0, // количество профитных серий LossSeries = 0, // количество убыточных сделок подряд EqualLosses = 0, // Общее количество убыточных сделок CountLosses = 0, // количество убыточных серий MaxLoss = 0, // Общий максимальный потенциальный убыток CurMaxProfit[], // Массив потенциальных прибылей последних ResultsPeriod сделок CurMaxLoss; // Максимальный убыток текущей сделки double OpenPrice = 0, // Цена открытия текущей сделки SLPrice = 0, // Уровень стоп-лосса текущей сделки TPPrice = 0; // Уровень профита текущей сделки datetime TimeOrder = 0; // Время открытия последней виртуальной сделки // -------------------------- //+-------------------------------------------------------------------------------------+ //| Функция инициализации эксперта | //+-------------------------------------------------------------------------------------+ int init() { //---- Activate = False; // - 1 - == Сбор информации об условиях торговли ======================================== Tick = MarketInfo(Symbol(), MODE_TICKSIZE); // минимальный тик Spread = ND(MarketInfo(Symbol(), MODE_SPREAD)*Point); // текщий спрэд StopLevel = ND(MarketInfo(Symbol(), MODE_STOPLEVEL)*Point); // текущий уровень стопов MinLot = MarketInfo(Symbol(), MODE_MINLOT); // минимальный разрешенный объем сделки MaxLot = MarketInfo(Symbol(), MODE_MAXLOT); // максимальный разрешенный объем сделки LotStep = MarketInfo(Symbol(), MODE_LOTSTEP); // шаг приращения объема сделки // - 1 - == Окончание блока ============================================================= // - 2 - == Приведение объема сделки к допустимому и проверка корректности объема ======= Lots = MathRound(Lots/LotStep)*LotStep; // округление объема до ближайшего допустимого if(Lots < MinLot || Lots > MaxLot) // объем сделки не меньше MinLot и не больше MaxLot { Comment("Параметром Lots был задан неправильный объем сделки! Советник отключен!"); return(0); } // - 2 - == Окончание блока ============================================================= // - 3 - == Обновление исторических данных ============================================== CurRed = 0; CurBlue = 0; Trade = -1; ProfitSeries = 0; EqualProfits = 0; CountProfits = 0; LossSeries = 0; EqualLosses = 0; CountLosses = 0; TimeOrder = 0; MaxLoss = 0; OpenPrice = 0; SLPrice = 0; TPPrice = 0; ArrayResize(CurMaxProfit, ResultsPeriod+1); ArrayResize(CurMaxLoss, ResultsPeriod+1); Comment("Подождите, производится сбор данных о работе эксперта на доступной истории"); for (int i = Bars-MathMax(AMKAPeriod, SlowEMAPeriod); i > 0; i--) { GetSignal(i); DoTransaction(i-1); } Comment(""); // - 3 - == Окончание блока ============================================================= LastBar = 0; Activate = True; // Все проверки успешно завершены, возводим флаг активизации эксперта //---- return(0); } //+-------------------------------------------------------------------------------------+ //| Функция деинициализации эксперта | //+-------------------------------------------------------------------------------------+ int deinit() { //---- Comment(""); //---- return(0); } //+-------------------------------------------------------------------------------------+ //| Приведение значений к точности одного пункта | //+-------------------------------------------------------------------------------------+ double ND(double A) { return(NormalizeDouble(A, Digits)); } //+-------------------------------------------------------------------------------------+ //| Расшифровка сообщения об ошибке | //+-------------------------------------------------------------------------------------+ string ErrorToString(int Error) { switch(Error) { case 2: return("зафиксирована общая ошибка, обратитесь в техподдержку."); case 5: return("у вас старая версия терминала, обновите ее."); case 6: return("нет связи с сервером, попробуйте перезагрузить терминал."); case 64: return("счет заблокирован, обратитесь в техподдержку."); case 132: return("рынок закрыт."); case 133: return("торговля запрещена."); case 149: return("запрещено локирование."); } } //+-------------------------------------------------------------------------------------+ //| Открытие позиции | //| Возвращает: | //| True - Позиция открыта успешно | //| False - Ошибка открытия | //+-------------------------------------------------------------------------------------+ bool OpenOrder(int Type, double Price, double SL, double TP) { // Блок проверки достаточности свободных средств if(AccountFreeMarginCheck(Symbol(), OP_BUY, Lots) <= 0 || GetLastError() == 134) { if(!FreeMarginAlert) { Print("Недостаточно средств для открытия позиции. Free Margin = ", AccountFreeMargin()); FreeMarginAlert = True; } return(False); } FreeMarginAlert = False; // --------------------------------------------- switch (Type) { case OP_BUY: string S = "BUY"; break; case OP_SELL: S = "SELL"; break; case OP_BUYSTOP: S = "BUYSTOP"; break; case OP_SELLSTOP: S = "SELLSTOP"; break; case OP_BUYLIMIT: S = "BUYLIMIT"; break; case OP_SELLLIMIT: S = "SELLLIMIT"; break; } if(WaitForTradeContext()) // ожидание освобождения торгового потока { Comment("Отправлен запрос на открытие ордера ", S, " ..."); int ticket=OrderSend(Symbol(), Type, Lots, Price, 0, SL, TP, NULL, MagicNumber, 0, CLR_NONE); // открытие позиции // Попытка открытия позиции завершилась неудачей if(ticket<0) { int Error = GetLastError(); if(Error == 2 || Error == 5 || Error == 6 || Error == 64 || Error == 132 || Error == 133 || Error == 149) // список фатальных ошибок { Comment("Фатальная ошибка при открытии позиции т. к. "+ ErrorToString(Error)+" Советник отключен!"); FatalError = True; } else Comment("Ошибка открытия позиции ", S, ": ", Error); // нефатальная ошибка return(False); } // --------------------------------------------- // Удачное открытие позиции Comment("Позиция ", S, " открыта успешно!"); PlaySound(OpenOrderSound); return(True); // ------------------------ } else { Comment("Время ожидания освобождения торгового потока истекло!"); return(False); } } //+-------------------------------------------------------------------------------------+ //| Ожидание торгового потока. Если поток свободен, то результат True, иначе - False | //+-------------------------------------------------------------------------------------+ bool WaitForTradeContext() { int P = 0; // цикл "пока" while(IsTradeContextBusy() && P < 5) { P++; Sleep(1000); } // ------------- if(P == 5) return(False); return(True); } //+-------------------------------------------------------------------------------------+ //| Расчет показаний AMKA и CloseONTheLimit_Reverse | //+-------------------------------------------------------------------------------------+ void GetSignal(int Bar) { Signal = 0; // - 1 - == Расчет по индикатору AMKA =================================================== double RedDot = iCustom(Symbol(), 0, "AMKA", AMKAPeriod, FastEMAPeriod, SlowEMAPeriod, PowLevel, dK, UseStdDev, AMKAPrice, 1, Bar); double BlueDot = iCustom(Symbol(), 0, "AMKA", AMKAPeriod, FastEMAPeriod, SlowEMAPeriod, PowLevel, dK, UseStdDev, AMKAPrice, 2, Bar); if (RedDot != 0 && BlueDot == 0) { CurRed = RedDot; CurBlue = 0.0; } if (BlueDot != 0 && RedDot == 0) { CurBlue = BlueDot; CurRed = 0.0; } // - 1 - == Окончание блока ============================================================= // - 2 - == Синтез сигнала ============================================================== if (CurRed != 0) if (ND(Open[Bar]) > ND(Close[Bar])) // последний бар медвежий if (ND(Close[Bar]) < ND(Low[Bar+1])) // и он выступает за границы предыдущего бара if (ND(Open[Bar+1]) < ND(Close[Bar+1])) // а второй бар бычий Signal = 1; if (CurBlue != 0) if (ND(Open[Bar]) < ND(Close[Bar])) // последний бар бычий if (ND(Close[Bar]) > ND(High[Bar+1])) // и он выступает за границы предыдущего бара if (ND(Open[Bar+1]) > ND(Close[Bar+1])) // а второй бар медвежий Signal = 2; // - 2 - == Окончание блока ============================================================= } //+-------------------------------------------------------------------------------------+ //| Запись прибыльной сделки | //+-------------------------------------------------------------------------------------+ void ProfitCount() { ProfitSeries++; // Увеличиваем количество сделок в серии EqualProfits++; // Увеличиваем общее количество прибыльных сделок if (LossSeries > 0) // Если до этого была убыточная серия { CountLosses++; // то увеличиваем количество серий на 1 LossSeries = 0; // и начинаем заново считать сделки в следующей убыточной серии } } //+-------------------------------------------------------------------------------------+ //| Запись убыточной сделки | //+-------------------------------------------------------------------------------------+ void LossCount() { LossSeries++; // Увеличиваем количество сделок в серии EqualLosses++; // Увеличиваем общее количество прибыльных сделок if (ProfitSeries > 0) // Если до этого была прибыльная серия { CountProfits++; // то увеличиваем количество серий на 1 ProfitSeries = 0; // и начинаем заново считать сделки в следующей прибыльной серии } } //+-------------------------------------------------------------------------------------+ //| Отбрасываем самое старое значение массива и освобождаем нулевой элемент | //+-------------------------------------------------------------------------------------+ void ThrowOld() { for (int i = ResultsPeriod; i > 0; i--) CurMaxProfit[i] = CurMaxProfit[i-1]; } //+-------------------------------------------------------------------------------------+ //| Находим среднее из значений элементов массива CurMaxProfit | //+-------------------------------------------------------------------------------------+ int AverageProfit() { double Res = 0; for (int i = 1; i < ResultsPeriod+1; i++) Res += CurMaxProfit[i]; return(MathRound(Res/(ResultsPeriod))); } //+-------------------------------------------------------------------------------------+ //| Совершение виртуальных сделок | //+-------------------------------------------------------------------------------------+ void DoTransaction(int Bar) { // - 1 - == Проверка срабатывания стопа или профита на предыдущей свече ================= if (Trade != -1) // если имеется открытая сделка if (Trade == 0) { // Длинная позиция if (ND(Low[Bar+1]) <= SLPrice) // Срабатывание стопа { Trade = -1; // закрываем виртуальную сделку LossCount(); } else if (ND(High[Bar+1]) >= TPPrice) // срабатывание профита { Trade = -1; // закрываем виртуальную сделку ProfitCount(); } CurMaxProfit[0] = MathMax(CurMaxProfit[0], (High[Bar+1] - OpenPrice)/Point); CurMaxLoss = MathMax(CurMaxLoss, (OpenPrice - Low[Bar+1])/Point); } else { // Короткая позиция if (ND(High[Bar+1]+Spread) >= SLPrice) // Срабатывание стопа { Trade = -1; // закрываем виртуальную сделку LossCount(); } else if (ND(Low[Bar+1]+Spread) <= TPPrice) // срабатывание профита { Trade = -1; // закрываем виртуальную сделку ProfitCount(); } CurMaxProfit[0] = MathMax(CurMaxProfit[0], (OpenPrice - Low[Bar+1] - Spread)/Point); CurMaxLoss = MathMax(CurMaxLoss, (High[Bar+1] + Spread - OpenPrice)/Point); } // - 1 - == Окончание блока ============================================================ // - 2 - == Имитация открытия длинной и закрытия короткой сделки ======================== if (Signal == 1 && Trade != 0) { double Price = ND(Open[Bar]+Spread); if (Trade == 1) // закрываем короткую, если имеется { if (OpenPrice-Price >= 0) ProfitCount(); else LossCount(); MaxLoss = MathMax(CurMaxLoss, MaxLoss); } Trade = 0; // Открытие длинной позиции TimeOrder = Time[Bar]; OpenPrice = Price; // Цена открытия сделки TPPrice = ND(Price + TakeProfit*Tick); // Профит сделки SLPrice = ND(Price - StopLoss*Tick); // Стоп сделки ThrowOld(); CurMaxProfit[0] = -(Spread/Point);// Текущая максимальная прибыль равна минус спрэд CurMaxLoss = Spread/Point; // Текущий максимальный убыток равен спрэду } // - 2 - == Окончание блока ============================================================ // - 3 - == Имитация открытия короткой и закрытия длинной сделки ======================== if (Signal == 2 && Trade != 1) { Price = ND(Open[Bar]); if (Trade == 0) // закрываем длинную, если имеется { if (Price-OpenPrice-Spread >= 0) ProfitCount(); else LossCount(); MaxLoss = MathMax(CurMaxLoss, MaxLoss); } Trade = 1; // Открытие короткой позиции TimeOrder = Time[Bar]; OpenPrice = Price; // Цена открытия сделки TPPrice = ND(Price - TakeProfit*Tick); // Профит сделки SLPrice = ND(Price + StopLoss*Tick); // Стоп сделки ThrowOld(); CurMaxProfit[0] = -(Spread/Point);// Текущая максимальная прибыль равна минус спрэд CurMaxLoss = Spread/Point; // Текущий максимальный убыток равен спрэду } // - 3 - == Окончание блока ============================================================ } //+-------------------------------------------------------------------------------------+ //| Закрывает все позиции типа Type. Если закрыть не удалось закрыть, то 1. | //| Если присутствует противоположная, то возвращает 2. В случае успеха 0. | //+-------------------------------------------------------------------------------------+ int CheckOrdersReal(int Type) { for (int i = OrdersTotal()-1; i >= 0; i--) if(OrderSelect(i, SELECT_BY_POS)) if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderType() < 2) // поиск "своей" сделки if(OrderType() == Type) // Если позиция типа Type { if (WaitForTradeContext()) { if(Type == OP_BUY) double Pr = ND(MarketInfo(Symbol(), MODE_BID)); else Pr = ND(MarketInfo(Symbol(), MODE_ASK)); if (!OrderClose(OrderTicket(), OrderLots(), Pr, 3))// то пытаемся закрыть ее return(1); // не удалось закрыть - вернем 1 } else return(1);//вернем 1, если не удалось дождаться освобождения торгового потока } else return(2); // вернем 2, если открыта позиция, противоположная указанной return(0); // если все ОК, то вернем 0 } //+-------------------------------------------------------------------------------------+ //| Замена стандартного блока "if-else" | //+-------------------------------------------------------------------------------------+ double IF(bool Condition, double IfTrue, double IfFalse) { if (Condition) return(IfTrue); // Если условие истинно, то возвращаем значение IfTrue else return(IfFalse); // Если условие ложно, то возвращаем значение IfFalse } //+-------------------------------------------------------------------------------------+ //| Функция START эксперта | //+-------------------------------------------------------------------------------------+ int start() { // - 1 - == Разрешено ли советнику работать? =========================================== if (!Activate || FatalError) // Отключается работа советника, если функция return(0); // init завершилась с ошибкой или имела место фатальная ошибка // - 1 - == Окончание блока ============================================================ // - 2 - == Контроль открытия нового бара ============================================== if (LastBar == Time[0]) //Если открытие на данном баре уже было return(0); // то заканчиваем // - 2 - == Окончание блока ============================================================ // - 3 - == Сбор информации об условиях торговли ======================================== Spread = ND(MarketInfo(Symbol(), MODE_SPREAD)*Point); // текщий спрэд StopLevel = ND(MarketInfo(Symbol(), MODE_STOPLEVEL)*Point); // текущий уровень стопов // - 3 - == Окончание блока ============================================================ // - 4 - == Расчет текущего сигнала ===================================================== GetSignal(1); // расчет сигнала DoTransaction(0); // Подсчет статистики if (CountProfits == 0) // Учитываем нулевое значение знаменателя int PC = EqualProfits; else PC = MathRound((EqualProfits/1.0)/CountProfits); // Расчет среднего выигрыша if (CountLosses == 0) // Учитываем нулевое значение знаменателя int LC = EqualLosses; else LC = MathRound((EqualLosses/1.0)/CountLosses); // Расчет среднего проигрыша Comment("Средняя серия прибыльных сделок ", PC, "\nСредняя серия убыточных сделок ", LC, "\nТекущее кол-во виртуальных прибыльных сделок ", ProfitSeries, "\nТекущее кол-во виртуальных убыточных сделок ", LossSeries, "\nМаксимальный потенциальный убыток ", MaxLoss, "\nСреднее значение потенциальной прибыли ", AverageProfit()); // - 4 - == Окончание блока ============================================================ double Price = 0; int Type = -1; // - 6 - == Открытие длинной позиции ==================================================== if (Signal == 1 && TimeOrder == Time[0]) { int Res = CheckOrdersReal(OP_SELL); RefreshRates(); if (Res == 0) // если нет открытых позиций { Price = ND(Ask); if (LossSeries > 0) { int NewTP = MathRound(TPKoef*AverageProfit()); int NewSL = SLKoef*MaxLoss; } else { NewTP = ArrayMinimum(CurMaxProfit, ResultsPeriod, 1); NewSL = NewTP+2*(Spread/Point); } double TP = ND(IF(NewTP > StopLevel/Point, Price+NewTP*Tick, Price + StopLevel)); double SL = ND(IF(NewSL > (StopLevel+Spread)/Point, Price-NewSL*Tick, Price - StopLevel-Spread)); Type = OP_BUY; } if (Res == 1) return(0); // не удалось закрыть противоположную } // - 6 - == Окончание блока ============================================================ // - 7 - == Установка ордера SellStop =================================================== if (Signal == 2 && TimeOrder == Time[0]) { Res = CheckOrdersReal(OP_BUY); if (Res == 0) // если нет открытых позиций { RefreshRates(); Price = ND(Bid); if (LossSeries > 0) { NewTP = MathRound(TPKoef*AverageProfit()); NewSL = SLKoef*MaxLoss; } else { NewTP = ArrayMinimum(CurMaxProfit, ResultsPeriod, 1); NewSL = NewTP+2*(Spread/Point); } TP = ND(IF(NewTP > StopLevel/Point, Price-NewTP*Tick, Price - StopLevel)); SL = ND(IF(NewSL > (StopLevel+Spread)/Point, Price+NewSL*Tick, Price + StopLevel + Spread)); Type = OP_SELL; } if (Res == 1) return(0); // не удалось закрыть противоположную } // - 7 - == Окончание блока ============================================================ if (Type >= 0) if (!OpenOrder(Type, Price, SL, TP)) // если не удалось установить ордер return(0); // то попробуем со следующим тиком LastBar = Time[0]; return(0); } //+------------------------------------------------------------------+