// MQ5 Converter class MQ5Converter { constructor(strategy) { this.strategy = strategy; this.parser = new RuleParser(); } generate() { const { parameters, buy_rules, sell_rules } = this.strategy; const symbol = parameters.symbol || 'EURUSD'; const atrPeriod = parameters.atr_period || 14; const slMultiplier = parameters.sl_multiplier || 2.0; const tpMultiplier = parameters.tp_multiplier || 3.0; // Generate random 6-digit magic number const magicNumber = Math.floor(100000 + Math.random() * 900000); const buyConditions = this.parser.parseRules(buy_rules, 'mq5'); // SELL rules use inverted operators const sellConditions = this.parser.parseRulesInverted(buy_rules, 'mq5'); return `//+------------------------------------------------------------------+ //| Strategy_${symbol}.mq5 | //| Generated by Strategy Converter | //+------------------------------------------------------------------+ #property copyright "FxMath Quant" #property link "https://fxmath.com" #property version "1.00" #include //=== TRADING SETTINGS === input group "=== Trade Settings ===" input double LotSize = 0.1; // Lot Size input int ATR_Period = ${atrPeriod}; // ATR Period input double SL_Multiplier = ${slMultiplier.toFixed(2)}; // SL ATR Multiplier input double TP_Multiplier = ${tpMultiplier.toFixed(2)}; // TP ATR Multiplier input ulong MagicNumber = ${magicNumber}; // Magic Number input string TradeComment = "FxMath EA"; // Trade Comment input int Slippage = 3; // Slippage //=== SL/TP SETTINGS === input group "=== SL/TP Settings ===" input bool EnableHardSL = true; // Enable Hard Stop Loss input bool EnableHardTP = true; // Enable Hard Take Profit //=== TRAILING STOP === input group "=== Trailing Stop ===" input bool EnableTrailing = false; // Enable Trailing Stop input double TrailingStart = 30; // Trailing Start (pips) input double TrailingStep = 10; // Trailing Step (pips) //=== BREAKEVEN === input group "=== Breakeven ===" input bool EnableBreakeven = false; // Enable Breakeven input double BreakevenStart = 20; // Breakeven Start (pips) input double BreakevenOffset = 2; // Breakeven Offset (pips) //=== TIME FILTER === input group "=== Time Filter ===" input bool EnableTimeFilter = false; // Enable Time Filter input int StartHour = 8; // Start Hour (Server Time) input int StartMinute = 0; // Start Minute input int EndHour = 22; // End Hour (Server Time) input int EndMinute = 0; // End Minute //=== SIGNAL SETTINGS === input group "=== Signal Settings ===" input bool CloseOnOpposite = false; // Close Trade on Opposite Signal //=== DISPLAY SETTINGS === input group "=== Display Settings ===" input bool ShowChartInfo = true; // Show Info on Chart // Global Variables CTrade trade; int atrHandle; double atrBuffer[]; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { // Set trade parameters trade.SetExpertMagicNumber(MagicNumber); trade.SetDeviationInPoints(Slippage); trade.SetTypeFilling(ORDER_FILLING_FOK); // Create ATR indicator handle atrHandle = iATR(_Symbol, PERIOD_CURRENT, ATR_Period); if(atrHandle == INVALID_HANDLE) { Print("Error creating ATR indicator"); return(INIT_FAILED); } ArraySetAsSeries(atrBuffer, true); Print("Strategy EA initialized for ${symbol}"); Print("Magic Number: ", MagicNumber); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { if(atrHandle != INVALID_HANDLE) IndicatorRelease(atrHandle); Print("Strategy EA deinitialized"); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { // Copy ATR values if(CopyBuffer(atrHandle, 0, 0, 2, atrBuffer) < 2) { Print("Error copying ATR buffer"); return; } double atrValue = atrBuffer[1]; // Check if we have an open position if(PositionSelect(_Symbol)) { // Position exists - manage it ManagePosition(atrValue); } else { // No position - check for entry signals // Check time filter if(EnableTimeFilter && !IsTimeAllowed()) return; // Check Buy Signal if(CheckBuySignal()) { OpenBuyOrder(atrValue); } // Check Sell Signal else if(CheckSellSignal()) { OpenSellOrder(atrValue); } } // Display chart info if(ShowChartInfo) DisplayChartInfo(); } //+------------------------------------------------------------------+ //| Check if current time is allowed for trading | //+------------------------------------------------------------------+ bool IsTimeAllowed() { MqlDateTime dt; TimeToStruct(TimeCurrent(), dt); int currentMinutes = dt.hour * 60 + dt.min; int startMinutes = StartHour * 60 + StartMinute; int endMinutes = EndHour * 60 + EndMinute; if(startMinutes < endMinutes) return (currentMinutes >= startMinutes && currentMinutes < endMinutes); else return (currentMinutes >= startMinutes || currentMinutes < endMinutes); } //+------------------------------------------------------------------+ //| Manage existing position | //+------------------------------------------------------------------+ void ManagePosition(double atrValue) { if(!PositionSelect(_Symbol)) return; long posType = PositionGetInteger(POSITION_TYPE); double posOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN); double posSL = PositionGetDouble(POSITION_SL); double posTP = PositionGetDouble(POSITION_TP); // Check for opposite signal if(CloseOnOpposite) { if(posType == POSITION_TYPE_BUY && CheckSellSignal()) { trade.PositionClose(_Symbol); return; } else if(posType == POSITION_TYPE_SELL && CheckBuySignal()) { trade.PositionClose(_Symbol); return; } } double currentPrice = (posType == POSITION_TYPE_BUY) ? SymbolInfoDouble(_Symbol, SYMBOL_BID) : SymbolInfoDouble(_Symbol, SYMBOL_ASK); double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT); double pipValue = point * 10; // Breakeven if(EnableBreakeven) { double profit = (posType == POSITION_TYPE_BUY) ? (currentPrice - posOpenPrice) : (posOpenPrice - currentPrice); if(profit >= BreakevenStart * pipValue) { double newSL = posOpenPrice + (BreakevenOffset * pipValue * ((posType == POSITION_TYPE_BUY) ? 1 : -1)); if((posType == POSITION_TYPE_BUY && newSL > posSL) || (posType == POSITION_TYPE_SELL && (posSL == 0 || newSL < posSL))) { trade.PositionModify(_Symbol, newSL, posTP); } } } // Trailing Stop if(EnableTrailing) { double profit = (posType == POSITION_TYPE_BUY) ? (currentPrice - posOpenPrice) : (posOpenPrice - currentPrice); if(profit >= TrailingStart * pipValue) { double newSL = currentPrice - (TrailingStep * pipValue * ((posType == POSITION_TYPE_BUY) ? 1 : -1)); if((posType == POSITION_TYPE_BUY && newSL > posSL) || (posType == POSITION_TYPE_SELL && (posSL == 0 || newSL < posSL))) { trade.PositionModify(_Symbol, newSL, posTP); } } } } //+------------------------------------------------------------------+ //| Display chart information | //+------------------------------------------------------------------+ void DisplayChartInfo() { string info = "\\n=== " + TradeComment + " ===\\n"; info += "Symbol: " + _Symbol + "\\n"; info += "Magic: " + IntegerToString(MagicNumber) + "\\n"; if(PositionSelect(_Symbol)) { info += "Position: " + EnumToString((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE)) + "\\n"; info += "Profit: " + DoubleToString(PositionGetDouble(POSITION_PROFIT), 2) + "\\n"; } else { info += "No Position\\n"; } Comment(info); } //+------------------------------------------------------------------+ //| Check Buy Signal | //+------------------------------------------------------------------+ bool CheckBuySignal() { return (${buyConditions.join(' &&\n ')}); } //+------------------------------------------------------------------+ //| Check Sell Signal | //+------------------------------------------------------------------+ bool CheckSellSignal() { return (${sellConditions.join(' &&\n ')}); } //+------------------------------------------------------------------+ //| Open Buy Order | //+------------------------------------------------------------------+ void OpenBuyOrder(double atrValue) { double price = SymbolInfoDouble(_Symbol, SYMBOL_ASK); double sl = EnableHardSL ? price - (atrValue * SL_Multiplier) : 0; double tp = EnableHardTP ? price + (atrValue * TP_Multiplier) : 0; sl = (sl > 0) ? NormalizeDouble(sl, _Digits) : 0; tp = (tp > 0) ? NormalizeDouble(tp, _Digits) : 0; if(trade.Buy(LotSize, _Symbol, price, sl, tp, TradeComment)) { Print("Buy order opened at ", price, " SL: ", sl, " TP: ", tp); } else { Print("Error opening buy order: ", GetLastError()); } } //+------------------------------------------------------------------+ //| Open Sell Order | //+------------------------------------------------------------------+ void OpenSellOrder(double atrValue) { double price = SymbolInfoDouble(_Symbol, SYMBOL_BID); double sl = EnableHardSL ? price + (atrValue * SL_Multiplier) : 0; double tp = EnableHardTP ? price - (atrValue * TP_Multiplier) : 0; sl = (sl > 0) ? NormalizeDouble(sl, _Digits) : 0; tp = (tp > 0) ? NormalizeDouble(tp, _Digits) : 0; if(trade.Sell(LotSize, _Symbol, price, sl, tp, TradeComment)) { Print("Sell order opened at ", price, " SL: ", sl, " TP: ", tp); } else { Print("Error opening sell order: ", GetLastError()); } } //+------------------------------------------------------------------+ `; } } window.MQ5Converter = MQ5Converter;