Здравствуйте все! Подскажите пожалуйста как проверить работу кода. На покупке идёт добавление к позиции, трейлинг работает нормально. На продаже добавление также срабатывает, но трейлинг-стоп и тейк-профит слетают. Изначальные показатели ТР и SL одинаковые для обоих типов сделок. Компилятор ошибки и предупреждения не находит. В коде не могу найти логическую ошибку
- Не срабатывают стопы.
- Дам денег за "модернизацию" (улучшение) советника!
- Любые вопросы новичков по MQL4 и MQL5, помощь и обсуждение по алгоритмам и кодам
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
input int ma_periodSlow = 70;
input int ma_periodFast = 30;
input int whole_array = 15;
input int PartialClosePoints = 300; // столько должна пройти цена для активации частичного закрытия позиции
input double AdditionFactor = 4; // множитель на сколько надо добавить позицию (0,5 = половина позиции)
//+------------------------------------------------------------------+
//| Defines |
//+------------------------------------------------------------------+
MqlRates bar[];
//+------------------------------------------------------------------+
//| Includes |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
//+------------------------------------------------------------------+
//| Global variables |
//+------------------------------------------------------------------+
double last_price = 0;
double eStep = 0;
MqlTick currentTick; //текущий тик символа
CTrade trade; //объект открытия закрытия позиций
//+------------------------------------------------------------------+
//| Inputs |
//+------------------------------------------------------------------+
input group "==== General ====";
static input long InpMagicnumber = 123456789; //магическое число
static input double InpLots = 1; //размер лота
input int InpStopLoss = 100; // стоплосс в пунктах (0=выключение)
input int InpTakeProfit = 100; // тэйкпрофит в пунктах (0=выключение)
input ushort Step = 20;
//+------------------------------------------------------------------+ //| Defines | //+------------------------------------------------------------------+ MqlRates bar[]; //+------------------------------------------------------------------+ //| Includes | //+------------------------------------------------------------------+ #include <Trade\Trade.mqh> //+------------------------------------------------------------------+ //| Global variables | //+------------------------------------------------------------------+ double last_price = 0; double eStep = 0; MqlTick currentTick; //текущий тик символа CTrade trade; //объект открытия закрытия позиций //+------------------------------------------------------------------+ //| Inputs | //+------------------------------------------------------------------+ input group "==== General ===="; static input long InpMagicnumber = 123456789; //магическое число static input double InpLots = 1; //размер лота input int InpStopLoss = 100; // стоплосс в пунктах (0=выключение) input int InpTakeProfit = 100; // тэйкпрофит в пунктах (0=выключение) input ushort Step = 20; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { ArraySetAsSeries(bar,true); //проверка входных данных if(!CheckInputs()) { return INIT_PARAMETERS_INCORRECT; } //получение магического числа trade.SetExpertMagicNumber(InpMagicnumber); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { // } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { CopyRates(_Symbol,PERIOD_CURRENT,0,5,bar); //создаем массив цен double priceEMAmassiveSlow[]; double priceEMAmassiveFast[]; int priceEMASlow = iMA(_Symbol,_Period,ma_periodSlow,0,MODE_EMA,PRICE_CLOSE); int priceEMAFast = iMA(_Symbol,_Period,ma_periodFast,0,MODE_EMA,PRICE_CLOSE); //установим сортировку цен в массиве от текущей свечи ArraySetAsSeries(priceEMAmassiveSlow,true); ArraySetAsSeries(priceEMAmassiveFast,true); //Параметры MA - линия - текущая свеча, 3 свечи - сохраним результат CopyBuffer(priceEMASlow,0,0,3,priceEMAmassiveSlow); CopyBuffer(priceEMAFast,0,0,3,priceEMAmassiveFast); //определим Ask, Bid double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits); double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits); // double posOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN); // double posVolume = PositionGetDouble(POSITION_VOLUME); // ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); //является ли новый тик тиком открытия нового бара if(!IsNewBar()) { return; } //получение тика текущего символа if(!SymbolInfoTick(_Symbol,currentTick)) { Print("ошибка получения текущего тика"); return; } //подсчёт открытых позиций int cntBuy, cntSell; if(!CountOpenPositions(cntBuy,cntSell)) { Print("ошибка получения подсчёта открытых позиций"); return; } //проверка для новой позиции на покупку if(cntBuy==0 && cntSell==0) { double Pattern1 = bar[2].open > bar[2].close && // поглощение bar[1].open <= bar[2].close && bar[1].close > bar[2].open && bar[1].close > priceEMAmassiveFast[0] && bar[1].open < priceEMAmassiveFast[0]; double Pattern2 = bar[3].open > bar[3].close && // три дня изнутри вверх // bar[3].high > bar[2].high && // bar[2].low > bar[3].low && bar[3].open >= bar[2].close && // bar[2].open >= bar[3].close && bar[1].close > bar[3].open && bar[1].close > priceEMAmassiveFast[0] && bar[1].open < priceEMAmassiveFast[0]; double Pattern3 = bar[2].open > bar[2].close && // завеса просвет bar[1].open < bar[2].close && bar[2].open > bar[1].close && bar[1].close > bar[1].open && bar[1].close > priceEMAmassiveFast[0] && bar[1].open < priceEMAmassiveFast[0]; double CandlePattern = Pattern1 || Pattern2 || Pattern3; if(Ask > priceEMAmassiveFast[0] && priceEMAmassiveFast[0] > priceEMAmassiveSlow[0] && CandlePattern) { //рассчёт стоплосса и тейкпрофита double sl = currentTick.bid - InpStopLoss * _Point; double tp = currentTick.bid + InpTakeProfit * _Point; if(!NormalizePrice(sl)) { return; } if(!NormalizePrice(tp)) { return; } trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,InpLots,currentTick.ask,sl,tp,"свечной паттерн"); } } //проверка для новой позиции на продажу if(cntSell==0 && cntBuy==0) { double Pattern1 = bar[2].open < bar[2].close && // поглощение bar[1].open >= bar[2].close && bar[1].close < bar[2].open && bar[1].close < priceEMAmassiveFast[0] && bar[1].open > priceEMAmassiveFast[0]; double Pattern2 = bar[3].open < bar[3].close && // три дня изнутри вниз // bar[3].high > bar[2].high && // bar[2].low > bar[3].low && bar[3].open <= bar[2].close && // bar[2].open <= bar[3].close && bar[1].close < bar[3].open && bar[1].close < priceEMAmassiveFast[0] && bar[1].open > priceEMAmassiveFast[0]; double Pattern3 = bar[2].open < bar[2].close && // завеса просвет bar[1].open > bar[2].close && bar[2].open < bar[1].close && bar[1].close < bar[1].open && bar[1].close < priceEMAmassiveFast[0] && bar[1].open > priceEMAmassiveFast[0]; double CandlePattern = Pattern1 || Pattern2 || Pattern3; if(Bid < priceEMAmassiveFast[0] && priceEMAmassiveFast[0] < priceEMAmassiveSlow[0] && CandlePattern) { //рассчёт стоплосса и тейкпрофита double sl = currentTick.ask + InpStopLoss * _Point; double tp = currentTick.ask - InpTakeProfit * _Point; if(!NormalizePrice(sl)) { return; } if(!NormalizePrice(tp)) { return; } trade.PositionOpen(_Symbol,ORDER_TYPE_SELL,InpLots,currentTick.bid,sl,tp,"свечной паттерн"); } } //трейлинг стоп! for(int i = PositionsTotal()-1; i >=0; i--) { ulong posTicket = PositionGetTicket(i); if(PositionSelectByTicket(posTicket)) { double posSl = PositionGetDouble(POSITION_SL); double posTp = PositionGetDouble(POSITION_TP); if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) { int shift = iHighest(_Symbol,PERIOD_CURRENT,MODE_HIGH,whole_array,1); double high = iHigh(_Symbol,PERIOD_CURRENT,shift); high = NormalizeDouble(high,_Digits); if(high < posSl) { //модификация стоплосса if(trade.PositionModify(posTicket,high,posTp)) { Print(__FUNCTION__," > Pos #",posTicket," was modified..."); } } } else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { int shift = iLowest(_Symbol,PERIOD_CURRENT,MODE_LOW,whole_array,1); double low = iLow(_Symbol,PERIOD_CURRENT,shift); low = NormalizeDouble(low,_Digits); if(low > posSl) { //модификация стоплосса if(trade.PositionModify(posTicket,low,posTp)) { Print(__FUNCTION__," > Pos #",posTicket," was modified..."); } } } } double posOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN); double posVolume = PositionGetDouble(POSITION_VOLUME); ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); //частичное закрытие позиции или добавление if(posVolume == InpLots) { double lotsToAddition = posVolume * AdditionFactor; lotsToAddition = NormalizeDouble(lotsToAddition,2); if(posType == POSITION_TYPE_SELL) { if(Ask < posOpenPrice - PartialClosePoints*_Point) { trade.PositionOpen(_Symbol,ORDER_TYPE_SELL,lotsToAddition,currentTick.bid,0,0,"добавление"); return; } } else if(posType == POSITION_TYPE_BUY) { if(Bid > posOpenPrice + PartialClosePoints*_Point) { trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,lotsToAddition,currentTick.ask,0,0,"добавление"); return; } } } } } //+------------------------------------------------------------------+ //| Custom functions | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CheckInputs() { if(InpMagicnumber<=0) { Alert("неправильные вводные: Магическое число <=0"); return false; } if(InpLots<=0) { Alert("неправильные вводные: Лот <=0"); return false; } if(InpStopLoss<0) { Alert("неправильные вводные: StopLoss <0"); return false; } if(InpTakeProfit<0) { Alert("неправильные вводные: TakeProfit <0"); return false; } return true; } //проверка если имеем тик бара открытия bool IsNewBar() { static datetime previousTime = 0; datetime currentTime = iTime(_Symbol,PERIOD_CURRENT,0); if(previousTime!=currentTime) { previousTime=currentTime; return true; } return false; } //подсчёт открытых позиций bool CountOpenPositions(int &cntBuy, int &cntSell) { cntBuy = 0; cntSell = 0; int total = PositionsTotal(); for(int i=total-1; i>=0; i--) { ulong ticket = PositionGetTicket(i); if(ticket<=0) { Print("Ошибка получения тикета позиции"); return false; } if(!PositionSelectByTicket(ticket)) { Print("ошибка выбора позиции"); return false; } long magic; if(!PositionGetInteger(POSITION_MAGIC,magic)) { Print("ошибка получения магического номера позиции"); return false; } if(magic==InpMagicnumber) { long type; if(!PositionGetInteger(POSITION_TYPE,type)) { Print("ошибка получения типа позиции"); return false; } if(type==POSITION_TYPE_BUY) { cntBuy++; } if(type==POSITION_TYPE_SELL) { cntSell++; } } } return true; } // нормализация цены bool NormalizePrice(double &price) { double tickSize=0; if(!SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_SIZE,tickSize)) { Print("ошибка получения размера тика"); return false; } price = NormalizeDouble(MathRound(price/tickSize)*tickSize,_Digits); return true; } //+------------------------------------------------------------------+z
Discover new MetaTrader 5 opportunities with MQL5 community and services
- 2025.11.28
- www.mql5.com
MQL5: language of trade strategies built-in the MetaTrader 5 Trading Platform, allows writing your own trading robots, technical indicators, scripts and libraries of functions
Aleksei Stepanenko #:
Неизвестно, что у Вас в коде, но так на вскидку если buy, работает корректно, а sell нет, то возможно, у Вас при sell переменная, которая потом сравнивается с текущей ценой инициализируется 0, а должна быть установлена в DBL_MAX
Неизвестно, что у Вас в коде, но так на вскидку если buy, работает корректно, а sell нет, то возможно, у Вас при sell переменная, которая потом сравнивается с текущей ценой инициализируется 0, а должна быть установлена в DBL_MAX
Спасибо за ответ. Мысль вашу понял. Код в комментарии выше.
А вот код появился. Кроме проверки, что high ниже стопа, чтобы поменять стоп на этот high, необходимо убедиться, что текущая цена находиться ниже этого high не менее двух спредов. При чем, для buy сравнивайте с ценой bid, а для sell с ask.
Aleksei Stepanenko #:
Просто на покупке, когда лоу выше стопа, то трейлинг меняется. а коды аналогичные. но на продажу не срабатывает.
А вот код появился. Кроме проверки, что high ниже стопа, чтобы поменять стоп на этот high, необходимо убедиться, что текущая цена находиться ниже этого high не менее двух спредов.
График рисуется по bid, и цена не может быть ниже low, а цена ask запросто может быть больше high. Поэтому у Вас стоп для sell не переносится.
Я сейчас не у компа, готовым кодом не помогу, сделайте примерно так:
Получите ask и bid из структуры MqlTick, дальше сравнивайте if(posSl- high>0 && high-2*ask+bid>0) , что означает что high выше верхней цены ask не менее, чем на один спред. Тоже самое нужно сделать для buy позиции.
Вы упускаете торговые возможности:
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Регистрация
Вход
Вы принимаете политику сайта и условия использования
Если у вас нет учетной записи, зарегистрируйтесь