// MQ4 Converter class MQ4Converter { 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, 'mql'); // SELL rules use inverted operators const sellConditions = this.parser.parseRulesInverted(buy_rules, 'mql'); return `//+------------------------------------------------------------------+ //| Strategy_${symbol}.mq4 | //| Generated by Strategy Converter | //+------------------------------------------------------------------+ #property copyright "FxMath Quant" #property link "https://fxmath.com" #property version "1.00" #property strict //=== 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 int MagicNumber = ${magicNumber}; // Magic Number input string TradeComment = "FxMath EA"; // Trade Comment input int Slippage = 3; // Slippage //=== SL/TP SETTINGS === input bool EnableHardSL = true; // Enable Hard Stop Loss input bool EnableHardTP = true; // Enable Hard Take Profit //=== 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 bool EnableBreakeven = false; // Enable Breakeven input double BreakevenStart = 20; // Breakeven Start (pips) input double BreakevenOffset = 2; // Breakeven Offset (pips) //=== 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 bool CloseOnOpposite = false; // Close Trade on Opposite Signal //=== DISPLAY SETTINGS === input bool ShowChartInfo = true; // Show Info on Chart // Global Variables double atrValue; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { Print("Strategy EA initialized for ${symbol}"); Print("Magic Number: ", MagicNumber); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { Print("Strategy EA deinitialized"); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { // Calculate ATR atrValue = iATR(Symbol(), 0, ATR_Period, 1); // Check for open positions bool hasPosition = false; for(int i = OrdersTotal() - 1; i >= 0; i--) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) { if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber) { hasPosition = true; ManagePosition(); break; } } } // If no position, check for entry signals if(!hasPosition) { // Check time filter if(EnableTimeFilter && !IsTimeAllowed()) return; // Check Buy Signal if(CheckBuySignal()) { OpenBuyOrder(); } // Check Sell Signal else if(CheckSellSignal()) { OpenSellOrder(); } } // Display chart info if(ShowChartInfo) DisplayChartInfo(); } //+------------------------------------------------------------------+ //| Check if current time is allowed for trading | //+------------------------------------------------------------------+ bool IsTimeAllowed() { int currentHour = Hour(); int currentMinute = Minute(); int currentMinutes = currentHour * 60 + currentMinute; 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() { if(!OrderSelect(0, SELECT_BY_POS, MODE_TRADES)) return; int orderType = OrderType(); double orderOpenPrice = OrderOpenPrice(); double orderSL = OrderStopLoss(); double orderTP = OrderTakeProfit(); // Check for opposite signal if(CloseOnOpposite) { if(orderType == OP_BUY && CheckSellSignal()) { if(!OrderClose(OrderTicket(), OrderLots(), Bid, Slippage, clrRed)) Print("Error closing buy order: ", GetLastError()); return; } else if(orderType == OP_SELL && CheckBuySignal()) { if(!OrderClose(OrderTicket(), OrderLots(), Ask, Slippage, clrGreen)) Print("Error closing sell order: ", GetLastError()); return; } } double currentPrice = (orderType == OP_BUY) ? Bid : Ask; double point = Point; double pipValue = point * 10; // Breakeven if(EnableBreakeven) { double profit = (orderType == OP_BUY) ? (currentPrice - orderOpenPrice) : (orderOpenPrice - currentPrice); if(profit >= BreakevenStart * pipValue) { double newSL = orderOpenPrice + (BreakevenOffset * pipValue * ((orderType == OP_BUY) ? 1 : -1)); if((orderType == OP_BUY && newSL > orderSL) || (orderType == OP_SELL && (orderSL == 0 || newSL < orderSL))) { if(!OrderModify(OrderTicket(), orderOpenPrice, newSL, orderTP, 0, clrBlue)) Print("Error modifying order for breakeven: ", GetLastError()); } } } // Trailing Stop if(EnableTrailing) { double profit = (orderType == OP_BUY) ? (currentPrice - orderOpenPrice) : (orderOpenPrice - currentPrice); if(profit >= TrailingStart * pipValue) { double newSL = currentPrice - (TrailingStep * pipValue * ((orderType == OP_BUY) ? 1 : -1)); if((orderType == OP_BUY && newSL > orderSL) || (orderType == OP_SELL && (orderSL == 0 || newSL < orderSL))) { if(!OrderModify(OrderTicket(), orderOpenPrice, newSL, orderTP, 0, clrBlue)) Print("Error modifying order for trailing stop: ", GetLastError()); } } } } //+------------------------------------------------------------------+ //| Display chart information | //+------------------------------------------------------------------+ void DisplayChartInfo() { string info = "\\n=== " + TradeComment + " ===\\n"; info += "Symbol: " + Symbol() + "\\n"; info += "Magic: " + IntegerToString(MagicNumber) + "\\n"; bool hasPosition = false; for(int i = OrdersTotal() - 1; i >= 0; i--) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) { if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber) { hasPosition = true; info += "Position: " + (OrderType() == OP_BUY ? "BUY" : "SELL") + "\\n"; info += "Profit: " + DoubleToStr(OrderProfit(), 2) + "\\n"; break; } } } if(!hasPosition) 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 price = 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; int ticket = OrderSend(Symbol(), OP_BUY, LotSize, price, Slippage, sl, tp, TradeComment, MagicNumber, 0, clrGreen); if(ticket > 0) { Print("Buy order opened at ", price, " SL: ", sl, " TP: ", tp); } else { Print("Error opening buy order: ", GetLastError()); } } //+------------------------------------------------------------------+ //| Open Sell Order | //+------------------------------------------------------------------+ void OpenSellOrder() { double price = 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; int ticket = OrderSend(Symbol(), OP_SELL, LotSize, price, Slippage, sl, tp, TradeComment, MagicNumber, 0, clrRed); if(ticket > 0) { Print("Sell order opened at ", price, " SL: ", sl, " TP: ", tp); } else { Print("Error opening sell order: ", GetLastError()); } } //+------------------------------------------------------------------+ `; } } window.MQ4Converter = MQ4Converter;