//+------------------------------------------------------------------+ //| Grid-EA mit MA-Kreuzung (H4 & H1) + alternative Aktivierung | //| - StartLots, MaxLots, LotMultiplier (Martingale) | //| - GridStep in Punkten | //| - TargetProfit (gemeinsam pro Richtung) | //| - startet Gegen-Grid falls Preis 200 Punkte (config) vom ersten | //| Grid-Einstieg läuft | //+------------------------------------------------------------------+ #property copyright "Dein Name" #property version "1.00" #property strict #include CTrade trade; //--------------------------------------------------------------------- // Eingaben //--------------------------------------------------------------------- input double StartLots = 0.10; // Start-Lotsize input double MaxLots = 5.00; // Maximale Lotsize input double LotMultiplier = 2.0; // Martingale-Faktor input int GridStep = 100; // Abstand zwischen Grid-Orders (Punkte) input double TargetProfit = 10.0; // Zielgewinn je Richtung (Kontowährung) input int FastMA = 50; // schnelle MA Periode input int SlowMA = 200; // langsame MA Periode input int MAPrice = PRICE_CLOSE; // Preistyp für MA input int MADirectionTF1 = PERIOD_H4; // Primäre TF (EA läuft auf H4 empfohlen) input int MADirectionTF2 = PERIOD_H1; // Sekundäre TF input int AltGridDistance = 200; // Punkte Abstand für alternative Grid-Start (z.B. 200) input int MagicNumber = 123456; // Magic Number input string CommentBuy = "GRID_BUY"; input string CommentSell = "GRID_SELL"; //--------------------------------------------------------------------- // interne Structs / Variablen //--------------------------------------------------------------------- bool buyGridActive = false; bool sellGridActive = false; //--------------------------------------------------------------------- // Hilfsfunktionen: Position-Handling (Hedge-Modus berücksichtigt) //--------------------------------------------------------------------- ulong PositionTicketByIndex(int index) { return(PositionGetTicket(index)); } int CountPositionsByDirection(int pos_type) { int cnt = 0; for(int i=PositionsTotal()-1; i>=0; i--) { ulong ticket = PositionGetTicket(i); if(ticket==0) continue; if(PositionSelectByTicket(ticket)) { string sym = PositionGetString(POSITION_SYMBOL); long magic = PositionGetInteger(POSITION_MAGIC); long ptype = PositionGetInteger(POSITION_TYPE); if(sym==_Symbol && magic==MagicNumber && ptype==pos_type) cnt++; } } return(cnt); } double GetFirstOpenPrice(int pos_type) { double price = 0.0; ulong first_ticket = 0; datetime first_time = 0; for(int i=PositionsTotal()-1; i>=0; i--) { ulong ticket = PositionGetTicket(i); if(ticket==0) continue; if(PositionSelectByTicket(ticket)) { string sym = PositionGetString(POSITION_SYMBOL); long magic = PositionGetInteger(POSITION_MAGIC); long ptype = PositionGetInteger(POSITION_TYPE); datetime opent = (datetime)PositionGetInteger(POSITION_TIME); if(sym==_Symbol && magic==MagicNumber && ptype==pos_type) { if(first_ticket==0 || opent < first_time) { first_ticket = ticket; first_time = opent; price = PositionGetDouble(POSITION_PRICE_OPEN); } } } } return(price); } double GetTotalProfitByDirection(int pos_type) { double profit = 0.0; for(int i=PositionsTotal()-1; i>=0; i--) { ulong ticket = PositionGetTicket(i); if(ticket==0) continue; if(PositionSelectByTicket(ticket)) { string sym = PositionGetString(POSITION_SYMBOL); long magic = PositionGetInteger(POSITION_MAGIC); long ptype = PositionGetInteger(POSITION_TYPE); if(sym==_Symbol && magic==MagicNumber && ptype==pos_type) profit += PositionGetDouble(POSITION_PROFIT); } } return(profit); } double GetLastLotSize(int pos_type) { double lastLot = StartLots; datetime newest = 0; for(int i=PositionsTotal()-1; i>=0; i--) { ulong ticket = PositionGetTicket(i); if(ticket==0) continue; if(PositionSelectByTicket(ticket)) { string sym = PositionGetString(POSITION_SYMBOL); long magic = PositionGetInteger(POSITION_MAGIC); long ptype = PositionGetInteger(POSITION_TYPE); datetime opent = (datetime)PositionGetInteger(POSITION_TIME); if(sym==_Symbol && magic==MagicNumber && ptype==pos_type) { if(opent > newest) { newest = opent; lastLot = PositionGetDouble(POSITION_VOLUME); } } } } return(lastLot); } void CloseAllByDirection(int pos_type) { for(int i=PositionsTotal()-1; i>=0; i--) { ulong ticket = PositionGetTicket(i); if(ticket==0) continue; if(PositionSelectByTicket(ticket)) { string sym = PositionGetString(POSITION_SYMBOL); long magic = PositionGetInteger(POSITION_MAGIC); long ptype = PositionGetInteger(POSITION_TYPE); if(sym==_Symbol && magic==MagicNumber && ptype==pos_type) { trade.SetExpertMagicNumber(MagicNumber); trade.PositionClose(ticket); } } } } bool PlaceMarketOrder(int order_type, double lots, string comment) { trade.SetExpertMagicNumber(MagicNumber); trade.SetExpertComment(comment); bool res=false; if(order_type==POSITION_TYPE_BUY) res = trade.Buy(lots, _Symbol, 0, 0, 0, comment); else res = trade.Sell(lots, _Symbol, 0, 0, 0, comment); if(!res) PrintFormat("Order failed: type=%d lots=%.2f err=%d (%s)", order_type, lots, GetLastError(), ErrorDescription(GetLastError())); return(res); } int MADirection() { double fastH4 = iMA(_Symbol, MADirectionTF1, FastMA, 0, MODE_SMA, MAPrice, 0); double slowH4 = iMA(_Symbol, MADirectionTF1, SlowMA, 0, MODE_SMA, MAPrice, 0); double fastH1 = iMA(_Symbol, MADirectionTF2, FastMA, 0, MODE_SMA, MAPrice, 0); double slowH1 = iMA(_Symbol, MADirectionTF2, SlowMA, 0, MODE_SMA, MAPrice, 0); int dirH4 = 0; if(fastH4 > slowH4) dirH4 = 1; else if(fastH4 < slowH4) dirH4 = -1; int dirH1 = 0; if(fastH1 > slowH1) dirH1 = 1; else if(fastH1 < slowH1) dirH1 = -1; if(dirH4==dirH1 && dirH4!=0) return(dirH4); return(0); } void ManageGridForDirection(int pos_type, string comment) { int orderCount = CountPositionsByDirection(pos_type); double totalProfit = GetTotalProfitByDirection(pos_type); double lastLot = GetLastLotSize(pos_type); double firstOpen = GetFirstOpenPrice(pos_type); if(orderCount>0 && totalProfit >= TargetProfit) { PrintFormat("%s TargetProfit erreicht (profit=%.2f). Schließe alle %s-Positionen.", comment, totalProfit, comment); CloseAllByDirection(pos_type); return; } if(orderCount==0) return; double distance = GridStep * _Point; double nextLot = MathMin(lastLot * LotMultiplier, MaxLots); if(nextLot < SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN)) nextLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN); double lastOpen = GetLastOpenPriceForDirection(pos_type); if(pos_type==POSITION_TYPE_BUY && lastOpen>0 && (Ask - lastOpen) >= distance) PlaceMarketOrder(POSITION_TYPE_BUY, nextLot, comment); if(pos_type==POSITION_TYPE_SELL && lastOpen>0 && (lastOpen - Bid) >= distance) PlaceMarketOrder(POSITION_TYPE_SELL, nextLot, comment); } double GetLastOpenPriceForDirection(int pos_type) { double price = 0.0; datetime newest = 0; for(int i=PositionsTotal()-1; i>=0; i--) { ulong ticket = PositionGetTicket(i); if(ticket==0) continue; if(PositionSelectByTicket(ticket)) { string sym = PositionGetString(POSITION_SYMBOL); long magic = PositionGetInteger(POSITION_MAGIC); long ptype = PositionGetInteger(POSITION_TYPE); datetime opent = (datetime)PositionGetInteger(POSITION_TIME); if(sym==_Symbol && magic==MagicNumber && ptype==pos_type) { if(opent > newest) { newest = opent; price = PositionGetDouble(POSITION_PRICE_OPEN); } } } } return(price); } void CheckAlternativeActivation() { int buyCount = CountPositionsByDirection(POSITION_TYPE_BUY); int sellCount = CountPositionsByDirection(POSITION_TYPE_SELL); double altDist = AltGridDistance * _Point; if(buyCount>0 && sellCount==0) { double buyFirst = GetFirstOpenPrice(POSITION_TYPE_BUY); if(buyFirst>0 && (buyFirst - Bid) >= altDist) { Print("Alternative Activation: Preis ist ", (buyFirst - Bid)/_Point, " Punkte unter erstem Buy -> starte Sell-Grid."); PlaceMarketOrder(POSITION_TYPE_SELL, StartLots, CommentSell); } } if(sellCount>0 && buyCount==0) { double sellFirst = GetFirstOpenPrice(POSITION_TYPE_SELL); if(sellFirst>0 && (Ask - sellFirst) >= altDist) { Print("Alternative Activation: Preis ist ", (Ask - sellFirst)/_Point, " Punkte über erstem Sell -> starte Buy-Grid."); PlaceMarketOrder(POSITION_TYPE_BUY, StartLots, CommentBuy); } } } int OnInit() { Print("Grid-EA initialisiert. Magic=", MagicNumber); return(INIT_SUCCEEDED); } void OnDeinit(const int reason) { Print("Grid-EA gestoppt."); } void OnTick() { int maDir = MADirection(); int buyCount = CountPositionsByDirection(POSITION_TYPE_BUY); int sellCount = CountPositionsByDirection(POSITION_TYPE_SELL); if(maDir==1 && buyCount==0) { Print("MA-Signal BUY auf H4+H1 -> starte initiale Buy-Order"); PlaceMarketOrder(POSITION_TYPE_BUY, StartLots, CommentBuy); } else if(maDir==-1 && sellCount==0) { Print("MA-Signal SELL auf H4+H1 -> starte initiale Sell-Order"); PlaceMarketOrder(POSITION_TYPE_SELL, StartLots, CommentSell); } CheckAlternativeActivation(); if(buyCount>0) ManageGridForDirection(POSITION_TYPE_BUY, CommentBuy); if(sellCount>0) ManageGridForDirection(POSITION_TYPE_SELL, CommentSell); }