//+------------------------------------------------------------------+ //| EA_XAU_Scalper_Martingale.mq4 | //| Simple scalper for XAUUSD with optional martingale averaging | //| - SMA(3)/SMA(20) crossover entry (configurable) | //| - Fixed TP/SL per order (in points) | //| - Optional Martingale: multiplier, max steps, distance (points) | //| - Close-all by total profit (money) | //+------------------------------------------------------------------+ #property strict #property copyright "Generated by ChatGPT" #property version "1.00" //--- input parameters input double LotsInitial = 0.01; // initial lot (e.g. 0.01 cent lot) input int SMA_Fast = 3; // fast SMA period input int SMA_Slow = 20; // slow SMA period input ENUM_TIMEFRAMES SMA_Timeframe = PERIOD_M5; // timeframe for SMA input bool UseCrossoverOnly = true; // use crossover on bar close input int TP_points = 100; // take profit in points (e.g. 100 points = 10 pip if 1 pip=10 point) input int SL_points = 150; // stop loss in points input bool UseMartingale = false; // enable martingale averaging input double MartingaleMultiplier = 2.0; // lot multiplier each averaging step input int MaxMartingaleSteps = 4; // maximum averaging steps (including initial = step 1) input int MartingaleDistancePoints = 300; // distance in points between averaging entries input double CloseAllProfitMoney = 2.0; // close all positions when total profit >= this amount (USD), 0 to disable input int MagicNumber = 20250831; // magic number input bool TradeOnMonday = true; input bool TradeOnFriday = true; input int MaxOrdersPerDirection = 10; //--- globals datetime lastBarTime = 0; //+------------------------------------------------------------------+ int OnInit() { lastBarTime = 0; return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ void OnDeinit(const int reason) { } //+------------------------------------------------------------------+ void OnTick() { // Only trade XAUUSD symbol string sym = Symbol(); // disable on markets other than XAUUSD if you want // Check daily trading day filters if(!IsTradingDay()) return; // Close all by total profit money if(CloseAllProfitMoney>0) { double totalProfit = GetTotalProfit(); if(totalProfit>=CloseAllProfitMoney) CloseAllPositions(); } // handle new bar based signals MqlRates rates[]; if(CopyRates(sym,SMA_Timeframe,0,3,rates)<=0) return; datetime curBar = rates[0].time; if(UseCrossoverOnly) { // on new bar if(curBar==lastBarTime) return; lastBarTime = curBar; // evaluate crossover double fastPrev = iMA(sym,SMA_Timeframe,SMA_Fast,0,MODE_SMA,PRICE_CLOSE,1); double slowPrev = iMA(sym,SMA_Timeframe,SMA_Slow,0,MODE_SMA,PRICE_CLOSE,1); double fastCur = iMA(sym,SMA_Timeframe,SMA_Fast,0,MODE_SMA,PRICE_CLOSE,0); double slowCur = iMA(sym,SMA_Timeframe,SMA_Slow,0,MODE_SMA,PRICE_CLOSE,0); // bullish crossover if(fastPrev<=slowPrev && fastCur>slowCur) { // open buy sequence (if not short positions open) if(!HasOppositeOrders(ORDER_TYPE_BUY)) OpenInitialOrder(ORDER_TYPE_BUY); } // bearish crossover if(fastPrev>=slowPrev && fastCurslow && !HasOppositeOrders(ORDER_TYPE_BUY)) OpenInitialOrder(ORDER_TYPE_BUY); if(fast=0;i--) { if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)) { if(OrderMagicNumber()!=MagicNumber) continue; tp += OrderProfit()+OrderSwap()+OrderCommission(); } } return(tp); } //+------------------------------------------------------------------+ void CloseAllPositions() { for(int i=OrdersTotal()-1;i>=0;i--) { if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)) { if(OrderMagicNumber()!=MagicNumber) continue; int type = OrderType(); bool res=false; if(type==OP_BUY) res = OrderClose(OrderTicket(),OrderLots(),Bid,5); if(type==OP_SELL) res = OrderClose(OrderTicket(),OrderLots(),Ask,5); } } } //+------------------------------------------------------------------+ bool HasOppositeOrders(int willOpenType) { // willOpenType: ORDER_TYPE_BUY or ORDER_TYPE_SELL // Check exist opposite orders for(int i=OrdersTotal()-1;i>=0;i--) { if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES)) continue; if(OrderMagicNumber()!=MagicNumber) continue; if(willOpenType==ORDER_TYPE_BUY && OrderType()==OP_SELL) return true; if(willOpenType==ORDER_TYPE_SELL && OrderType()==OP_BUY) return true; } return false; } //+------------------------------------------------------------------+ void OpenInitialOrder(int dir) { string sym = Symbol(); double lots = LotsInitial; double price = (dir==ORDER_TYPE_BUY)? Ask : Bid; double sl = (dir==ORDER_TYPE_BUY)? price - SL_points*Point : price + SL_points*Point; double tp = (dir==ORDER_TYPE_BUY)? price + TP_points*Point : price - TP_points*Point; int ticket = OrderSend(sym,(dir==ORDER_TYPE_BUY?OP_BUY:OP_SELL),lots,price,5,sl,tp,"XAU_Scalper",MagicNumber,0,clrBlue); if(ticket<0) { int err = GetLastError(); Print("OrderSend failed: ",err); ResetLastError(); } } //+------------------------------------------------------------------+ void ManageMartingale() { string sym = Symbol(); // For each direction, check last order and place averaging if price reached distance // BUY side ManageDirectionMartingale(OP_BUY); // SELL side ManageDirectionMartingale(OP_SELL); } //+------------------------------------------------------------------+ void ManageDirectionMartingale(int dir) { // Count existing orders of this magic and type int count=0; double lastPrice=0.0; double lotsLast=0.0; int lastTicket=0; for(int i=0;i0 && OrderOpenTime()>=lastPrice){} // find most recent order (by ticket) if(OrderTicket()>lastTicket) { lastTicket=OrderTicket(); lastPrice=OrderOpenPrice(); lotsLast=OrderLots(); } } if(dir==OP_SELL && OrderType()==OP_SELL) { count++; if(OrderTicket()>lastTicket) { lastTicket=OrderTicket(); lastPrice=OrderOpenPrice(); lotsLast=OrderLots(); } } } if(count==0) return; // no base order to average if(count>=MaxMartingaleSteps) return; // reached max // determine current price and check distance double curPrice = (dir==OP_BUY)? Ask : Bid; double distPoints = MathAbs(curPrice - lastPrice)/Point; if(distPoints >= MartingaleDistancePoints) { // place next averaging order double nextLots = NormalizeLot(lotsLast*MartingaleMultiplier); // safety: do not exceed a maximum per direction if(count+1 > MaxOrdersPerDirection) return; double sl = (dir==OP_BUY)? curPrice - SL_points*Point : curPrice + SL_points*Point; double tp = (dir==OP_BUY)? curPrice + TP_points*Point : curPrice - TP_points*Point; int ticket = OrderSend(sym,(dir==OP_BUY?OP_BUY:OP_SELL),nextLots,curPrice,5,sl,tp,"XAU_Scalper_AVG",MagicNumber,0,clrRed); if(ticket<0) { Print("Martingale OrderSend failed: ",GetLastError()); ResetLastError(); } } } //+------------------------------------------------------------------+ double NormalizeLot(double lot) { // Normalize to broker lot step (assume 0.01 min step) double step = MarketInfo(Symbol(),MODE_LOTSTEP); double minlot = MarketInfo(Symbol(),MODE_MINLOT); double maxlot = MarketInfo(Symbol(),MODE_MAXLOT); double l = MathMax(minlot,MathFloor(lot/step+0.5)*step); if(l>maxlot) l = maxlot; return(l); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+