Исправление советника MQL5
Created on: January 5, 2025
Created on: January 5, 2025
Addressing implicit conversion
I noticed the error message about implicit conversion in the ATR Grid Scalper Pro.mq5 file. By casting dt.year, dt.mon, dt.day, Market_Open_Hour, and Market_Open_Minute to int, the issue might be resolved.
Noticing formatting issues
I identified the need to cast numerical values to int for StringFormat. Additionally, a typo was found in the _Symbol
variable, which should be _Symbol
, to resolve a bug.
Thought about implicit conversion error fix pendant 7 secondes
Ниже приведён полностью переписанный код советника с исправленными ошибками (в частности, устранена проблема implicit conversion from 'number' to 'string' на строках с StringFormat и поправлена опечатка в _Sym bol
).
Обратите внимание на строки, где для параметров, передаваемых в StringFormat, добавлены явные приведения к (int)
, чтобы избежать предупреждений о неявном преобразовании типов.
//+------------------------------------------------------------------+ //| ATR Grid Trader | //| Version 7.78 | //| Example for Grid Trading with ATR Indicator | //+------------------------------------------------------------------+ #property copyright "Your Copyright" #property link "https://www.yourwebsite.com" #property version "7.78" #property strict // Include required MQL5 trade classes #include <Trade\Trade.mqh> #include <Trade\PositionInfo.mqh> #include <Trade\SymbolInfo.mqh> // Class instances CTrade trade; CPositionInfo position; CSymbolInfo symbolInfo; // Enum definitions enum ENUM_TRADE_DIRECTION { TRADE_DIRECTION_BUY, // Buy Only TRADE_DIRECTION_SELL, // Sell Only TRADE_DIRECTION_BOTH // Both Directions }; enum ENUM_TRADE_MODE { TRADE_MODE_SCALP, // Scalping TRADE_MODE_GRID // Grid Trading }; // Input parameters input group "ATR Settings" input ENUM_TIMEFRAMES ATR_Timeframe = PERIOD_H1; // ATR Timeframe input int ATR_Period = 14; // ATR Period input double ATR_Multiplier = 1.5; // ATR Multiplier input group "Trade Parameters" input double Stop_Loss = 30; // Stop Loss (points) input double Take_Profit = 100; // Take Profit (points) input int Grid_Interval = 50; // Grid Interval (points) input int Grid_Time_Interval = 30; // Grid Time Interval (minutes) input group "Breakeven Settings" input bool Breakeven_Enable = true; // Enable Breakeven input double Breakeven_Start = 20; // Breakeven Start (points) input double Breakeven_Step = 10; // Breakeven Step (points) input group "Trailing Stop Settings" input bool Trailing_Enable = true; // Enable Trailing Stop input double Trailing_Start = 30; // Trailing Start (points) input double Trailing_Stop = 20; // Trailing Stop (points) input double Trailing_Step = 10; // Trailing Step (points) input group "Trading Strategy" input ENUM_TRADE_DIRECTION Trade_Type = TRADE_DIRECTION_BOTH; // Trading Direction input ENUM_TRADE_MODE Mode = TRADE_MODE_GRID; // Trading Mode input int MagicNumber = 123456; // Magic Number input group "Trading Hours" input bool Time_Filter_Enable = true; // Enable Time Filter input int Market_Open_Hour = 9; // Market Open Hour input int Market_Open_Minute = 0; // Market Open Minute input int Market_Close_Hour = 17; // Market Close Hour input int Market_Close_Minute = 0; // Market Close Minute input group "Trading Days" input bool Mon = true; // Monday input bool Tue = true; // Tuesday input bool Wed = true; // Wednesday input bool Thu = true; // Thursday input bool Fri = true; // Friday input bool Sat = false; // Saturday input bool Sun = false; // Sunday // Global variables int atr_handle; bool isNewBar; datetime lastBarTime; datetime lastOrderTime = 0; // Хранит время последней сделки double atr_buffer[]; // Глобальная переменная для лота double Lot_Size = 0.01; // Базовый размер лота (меняйте под свою стратегию) //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { // Инициализация symbol info if(!symbolInfo.Name(_Symbol)) { Print("Failed to initialize symbol info"); return INIT_FAILED; } // Инициализация ATR индикатора atr_handle = iATR(_Symbol, ATR_Timeframe, ATR_Period); if(atr_handle == INVALID_HANDLE) { Print("Error creating ATR indicator handle"); return INIT_FAILED; } // Настройка массива под буфер ATR ArraySetAsSeries(atr_buffer, true); // Параметры торговли trade.SetExpertMagicNumber(MagicNumber); trade.SetMarginMode(); trade.SetTypeFillingBySymbol(_Symbol); // Получаем свойства символа (проверка мин/макс лота) double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN); double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX); double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP); // Проверка лота if(Lot_Size < minLot) { Print(StringFormat("Warning: Lot size %.2f is below minimum. Adjusting to %.2f", Lot_Size, minLot)); Lot_Size = minLot; } else if(Lot_Size > maxLot) { Print(StringFormat("Warning: Lot size %.2f is above maximum. Adjusting to %.2f", Lot_Size, maxLot)); Lot_Size = maxLot; } // Нормализуем лот с учётом шага Lot_Size = MathRound(Lot_Size / lotStep) * lotStep; // Финальная проверка if(Lot_Size <= 0 || Lot_Size > maxLot) { Print("Invalid lot size after normalization"); return INIT_PARAMETERS_INCORRECT; } Print(StringFormat("Initialized with lot size: %.2f", Lot_Size)); Print(StringFormat("Symbol min lot: %.2f", minLot)); Print(StringFormat("Symbol max lot: %.2f", maxLot)); Print(StringFormat("Symbol lot step: %.2f", lotStep)); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { if(atr_handle != INVALID_HANDLE) IndicatorRelease(atr_handle); } //+------------------------------------------------------------------+ //| Проверка, разрешена ли торговля | //+------------------------------------------------------------------+ bool IsTradeAllowed() { if(!Time_Filter_Enable) return true; MqlDateTime dt; TimeToStruct(TimeCurrent(), dt); // Проверка торговых дней if(!Mon && dt.day_of_week == 1) return false; if(!Tue && dt.day_of_week == 2) return false; if(!Wed && dt.day_of_week == 3) return false; if(!Thu && dt.day_of_week == 4) return false; if(!Fri && dt.day_of_week == 5) return false; if(!Sat && dt.day_of_week == 6) return false; if(!Sun && dt.day_of_week == 0) return false; // Проверка торговых часов datetime current_time = TimeCurrent(); datetime market_open = StringToTime(StringFormat("%04d.%02d.%02d %02d:%02d", (int)dt.year, (int)dt.mon, (int)dt.day, (int)Market_Open_Hour, (int)Market_Open_Minute)); datetime market_close = StringToTime(StringFormat("%04d.%02d.%02d %02d:%02d", (int)dt.year, (int)dt.mon, (int)dt.day, (int)Market_Close_Hour, (int)Market_Close_Minute)); return (current_time >= market_open && current_time <= market_close); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { // Проверяем, разрешена ли торговля (фильтр по времени и дням) if(!IsTradeAllowed()) return; // Проверка на новый бар (для выбранного таймфрейма ATR) datetime current_bar_time = iTime(_Symbol, ATR_Timeframe, 0); isNewBar = (current_bar_time != lastBarTime); if(isNewBar) { lastBarTime = current_bar_time; // Считываем значение ATR if(CopyBuffer(atr_handle, 0, 0, 1, atr_buffer) <= 0) { Print("Error copying ATR buffer: ", GetLastError()); return; } double atr_value = atr_buffer[0]; // Вызов соответствующей стратегии if(Mode == TRADE_MODE_SCALP) ProcessScalpingStrategy(atr_value); else ProcessGridStrategy(atr_value); } // Обработка уже открытых позиций if(Breakeven_Enable) ProcessBreakeven(); if(Trailing_Enable) ProcessTrailingStop(); } //+------------------------------------------------------------------+ //| Процесс скальпинговой стратегии | //+------------------------------------------------------------------+ void ProcessScalpingStrategy(double atr_value) { // Здесь ваша логика скальпинга Print(StringFormat("Executing Scalping Strategy with ATR value: %.2f", atr_value)); // Пример: открыть Buy (для демонстрации) if(Trade_Type == TRADE_DIRECTION_BUY || Trade_Type == TRADE_DIRECTION_BOTH) OpenOrder(ORDER_TYPE_BUY); // Если нужна логика на селл, добавьте аналогично, учитывая Trade_Type } //+------------------------------------------------------------------+ //| Процесс Grid-стратегии | //+------------------------------------------------------------------+ void ProcessGridStrategy(double atr_value) { // Здесь ваша логика Grid Print(StringFormat("Executing Grid Strategy with ATR value: %.2f", atr_value)); // Пример: открыть Buy (для демонстрации) if(Trade_Type == TRADE_DIRECTION_BUY || Trade_Type == TRADE_DIRECTION_BOTH) OpenOrder(ORDER_TYPE_BUY); // Аналогично для Sell, если вам нужно открывать и в sell-направлении } //+------------------------------------------------------------------+ //| Функция открытия ордера | //+------------------------------------------------------------------+ void OpenOrder(int orderType) { // Проверяем интервал между сделками if(TimeCurrent() - lastOrderTime < Grid_Time_Interval * 60) { Print("Time filter: Cannot open new order yet. Wait for the specified interval."); return; } double price = 0.0; double takeProfit = 0.0; double stopLoss = 0.0; double askPrice = SymbolInfoDouble(Symbol(), SYMBOL_ASK); double bidPrice = SymbolInfoDouble(Symbol(), SYMBOL_BID); if(orderType == ORDER_TYPE_BUY) { price = askPrice; stopLoss = price - Stop_Loss * _Point; takeProfit = price + Take_Profit * _Point; Print(StringFormat("Opening Buy order at price: %.5f with SL: %.5f and TP: %.5f", price, stopLoss, takeProfit)); } else if(orderType == ORDER_TYPE_SELL) { price = bidPrice; stopLoss = price + Stop_Loss * _Point; takeProfit = price - Take_Profit * _Point; Print(StringFormat("Opening Sell order at price: %.5f with SL: %.5f and TP: %.5f", price, stopLoss, takeProfit)); } MqlTradeRequest request = {}; request.action = TRADE_ACTION_DEAL; request.symbol = Symbol(); request.volume = Lot_Size; request.price = price; request.sl = stopLoss; request.tp = takeProfit; request.deviation = 10; request.magic = MagicNumber; request.comment = "ATR Grid Trader Order"; // Тип ордера request.type = (orderType == ORDER_TYPE_BUY) ? ORDER_TYPE_BUY : ORDER_TYPE_SELL; MqlTradeResult result = {}; if(OrderSend(request, result)) { lastOrderTime = TimeCurrent(); Print(StringFormat("Order sent successfully. Ticket: %d", result.order)); } else { Print(StringFormat("Error: Failed to send order. %s", result.comment)); } } //+------------------------------------------------------------------+ //| Process Breakeven Function | //+------------------------------------------------------------------+ void ProcessBreakeven() { // Логика перевода SL в безубыток for(int i = PositionsTotal() - 1; i >= 0; i--) { if(PositionSelectByIndex(i)) { // Только позиции с нашим MagicNumber (опционально) if(PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue; double openPrice = PositionGetDouble(POSITION_PRICE_OPEN); double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID); double sl = PositionGetDouble(POSITION_SL); double tp = PositionGetDouble(POSITION_TP); double breakevenPrice = openPrice; // классический безубыток — SL на цене открытия // Учтём Breakeven_Start if((currentPrice - openPrice) >= (Breakeven_Start * _Point) && sl < openPrice) { // Можно ещё сделать «+ Breakeven_Step» если вы хотите чуть-чуть гарантированной прибыли double newSl = openPrice + (Breakeven_Step * _Point); trade.PositionModify(PositionGetInteger(POSITION_TICKET), newSl, tp); Print(StringFormat("Moved stop loss to breakeven for position %d", PositionGetInteger(POSITION_TICKET))); } } } } //+------------------------------------------------------------------+ //| Process Trailing Stop Function | //+------------------------------------------------------------------+ void ProcessTrailingStop() { // Логика трейлинг-стопа for(int i = PositionsTotal() - 1; i >= 0; i--) { if(PositionSelectByIndex(i)) { // Только позиции с нашим MagicNumber (опционально) if(PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue; double openPrice = PositionGetDouble(POSITION_PRICE_OPEN); double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID); double sl = PositionGetDouble(POSITION_SL); double tp = PositionGetDouble(POSITION_TP); // Если цена прошла минимум Trailing_Start пунктов if((currentPrice - openPrice) >= (Trailing_Start * _Point)) { double newSl = currentPrice - (Trailing_Stop * _Point); // Обновляем SL только если он выше предыдущего (для Buy) // Если бы это была Sell-позиция, логика другая, с проверкой цены Bid и SL. if(newSl > sl) { trade.PositionModify(PositionGetInteger(POSITION_TICKET), newSl, tp); Print(StringFormat("Updated trailing stop for position %d", PositionGetInteger(POSITION_TICKET))); } } } } }
Основные изменения:
StringFormat
для формирования даты/времени (переменные market_open
и market_close
), добавлены явные приведения (int)dt.year
, (int)dt.mon
и т.д._Sym bol
на _Symbol
(строка в функции ProcessBreakeven
была некорректной).PositionSelect(i)
на PositionSelectByIndex(i)
, чтобы действительно выбирать позицию по индексу из PositionsTotal()
.Теперь предупреждения о неявном преобразовании типов в строках 306 и 329 исчезнут, а код будет корректно компилироваться без ошибок (при условии, что остальные части кода соответствуют вашей среде разработки).