DE40 : Capital Management with a Dynamic Basket TP – Implementation

Viewing 1 post (of 1 total)
  • Author
    Posts
  • #265385 quote
    JohnScherJohnScher
    Participant
    Veteran

    Hello everyone,

    I would like to reproduce an existing MT5 trading logic in ProRealTime / ProBacktest, mainly in order to test it on the longest possible historical DE40 data series available in PRT.

    The focus is not on optimizing the entry logic, but on the capital management.

    The basic idea is:

    • every new position has the same fixed size
    • as long as only one position is open, it is treated as a standalone trade
    • as soon as a second position is added, a basket is created
    • from that moment on, a fixed capital profit target is defined for the whole basket
    • example: EUR 1,000 virtual capital with a 5% basket target = EUR 50 target profit
    • the basket profit target remains fixed
    • the common TP price is recalculated after every new entry
    • all open basket positions share the same common target price
    • if another position is added, the TP of the whole basket changes accordingly
    • the complete basket is closed when the predefined capital target is reached
    • position size is never increased

    In short:

    Capital target fixed – TP price dynamic.

    This is not intended as a martingale system and not as a classic fixed-distance grid. The position size remains constant.

    Example:

    With two open positions, the common TP should be calculated so that both positions together produce the predefined basket profit.

    If a third position is added, the common TP should be recalculated so that all three positions together still reach the same fixed capital target.

    The main purpose of the backtest is to evaluate the capital-management behaviour over a long DE40 history.

    The statistics I am especially interested in are:

    • maximum floating drawdown
    • maximum number of simultaneously open positions
    • longest basket duration
    • maximum exposure / capital requirement
    • behaviour during long bear markets
    • behaviour in different market regimes

    I will add the existing MT5 code below. It should be understood as a reference implementation of the intended logic and does not need to be translated line by line.

    If SET TARGET %PROFIT is not suitable for cumulative positions, the common basket target price would need to be calculated explicitly and the complete position closed at that price.

    The underlying entry logic is simple and is not the main point of this discussion.

    Any help with a clean ProRealTime / ProBacktest implementation of this capital-management logic would be appreciated.



    MT5 code follows here:

    (Please note: the MT5 code is provided only as a reference for the trading and capital-management logic. I am not asking for a review of the EA’s MT5-specific robustness, retry handling, logging, persistence, or broker execution details.)


    //+——————————————————————+

    //|           D209_1HL_D522_D1HighLow_Basket.mq5 |

    //|                       https://www.dkatle.com |

    //|                       Copyright dkatle 2026 |

    //+——————————————————————+


    #property strict

    #property copyright “dkatle 2026”

    #property link   “https://www.dkatle.com”

    #property version  “6.4”


    #include <Trade/Trade.mqh>

    #include <Trade/PositionInfo.mqh>


    CTrade     trade;

    CPositionInfo posInfo;


    // — Input Parameter —

    input string     TradeComment     = “D209 1HL D522 D1HiLo Basket”;

    input long      Magic         = 2090522063


    input group “Kapital & Basket Einstellungen”

    input double     InitialVirtualCapital = 1000.0;

    input double     BasketTPPercent    = 5.0;

    input bool      CumulateOrders    = true;


    input group “Handels Parameter”

    input double     FixedLotSize     = 0.1;

    input double     StopLossPercent    = 0.0;

    input double     TakeProfitPercent   = 2.5;


    input group “Einstiegs-Zeitpunkt (Slot)”

    input string     InpHolidays      = “01.01, 01.05, 03.10, 24.12, 25.12, 26.12, 31.12”;

    input int      BlockMonth1      = 0;

    input int      BlockMonth2      = 0;

    input int      BlockMonth3      = 0;

    input int      BlockMonth4      = 0;

    input bool      UseBerlinOffset    = false;

    input int      BerlinOffsetHours   = +1;

    input bool      InpTradeMonday    = false;

    input bool      InpTradeTuesday    = true;

    input bool      InpTradeWednesday   = false;

    input bool      InpTradeThursday   = false;

    input bool      InpTradeFriday    = false;

    input int      InpEntryHour     = 09;

    input int      InpEntryMinute    = 00;


    input group “Ausstiegs-Zeitpunkt (Slot & Wochentag für Einzelläufer)”

    input bool      InpExitEnabled    = false;

    input bool      InpExitMonday     = false;

    input bool      InpExitTuesday    = true;

    input bool      InpExitWednesday   = false;

    input bool      InpExitThursday    = false;

    input bool      InpExitFriday     = true;

    input int      InpExitHour      = 22;

    input int      InpExitMinute     = 00;


    input group “Robustheit / Retry”

    input int  EntryWindowSeconds   = 60;

    input int  RetryIntervalMs     = 500;

    input int  CloseRetryIntervalHours = 1;

    input int  MaxSpreadPoints     = 100;

    input int  MaxSlippagePoints    = 50;


    // — Globale Variablen —

    string  lblStart, lblCurr, lblTarget, logFileName;

    datetime lastProcessedEntrySlot = 0;

    ulong  lastEntryAttemptMs   = 0;

    bool   basketActive      = false;

    double  basketLockedTarget   = 0.0;

    bool   targetCloseActive    = false;

    double  targetCloseLockedTarget = 0.0;


    // — Hilfs-Namen für globale Variablen im Terminal —

    string GV_TargetName(ulong ticket) { return “D113_Exit_” + (string)Magic + “_” + (string)ticket + “_Target”; }

    string GV_NextName(ulong ticket)  { return “D113_Exit_” + (string)Magic + “_” + (string)ticket + “_Next”; }

    string GV_LastEntrySlotName()   { return “D113_LastEntry_” + (string)Magic + “_” + _Symbol; }

    string GV_BasketTargetName()    { return “D113_BasketTarget_” + (string)Magic + “_” + _Symbol; }

    string GV_TargetCloseName()    { return “D113_BasketClose_” + (string)Magic + “_” + _Symbol; }


    //+——————————————————————+

    //| Hilfsfunktionen                          |

    //+——————————————————————+

    int GetOpenPositionsCount()

    {

      int count = 0;

      for(int i = PositionsTotal() – 1; i >= 0; i–)

      {

       if(posInfo.SelectByIndex(i) && posInfo.Magic() == Magic && posInfo.Symbol() == _Symbol)

         count++;

      }

      return count;

    }


    bool IsTradeRetcodeAccepted()

    {

      uint rc = trade.ResultRetcode();

      return (rc == TRADE_RETCODE_DONE ||

          rc == TRADE_RETCODE_DONE_PARTIAL ||

          rc == TRADE_RETCODE_PLACED);

    }


    string TradeResultText()

    {

      return “Retcode=” + (string)trade.ResultRetcode() +

         ” (” + trade.ResultRetcodeDescription() + “)” +

         “, Order=” + (string)trade.ResultOrder() +

         “, Deal=” + (string)trade.ResultDeal();

    }


    bool ClosePositionVerified(ulong ticket)

    {

      if(!PositionSelectByTicket(ticket))

       return true;


      trade.SetDeviationInPoints(MaxSlippagePoints);

      ResetLastError();


      bool requestOk = trade.PositionClose(ticket);

      bool accepted = requestOk && IsTradeRetcodeAccepted();


      bool stillOpen = PositionSelectByTicket(ticket);


      if(accepted && !stillOpen)

       return true;


      Print(“D308 CLOSE nicht vollständig ausgeführt. Ticket=”, ticket,

         “, RequestOK=”, requestOk,

         “, “, TradeResultText(),

         “, LastError=”, GetLastError());

      return false;

    }


    void MarkEntrySlotProcessed(datetime slotStart)

    {

      lastProcessedEntrySlot = slotStart;

      GlobalVariableSet(GV_LastEntrySlotName(), (double)slotStart);

    }


    void ActivateBasket(double target)

    {

      basketActive    = true;

      basketLockedTarget = target;

      GlobalVariableSet(GV_BasketTargetName(), target);

    }


    void DeactivateBasket()

    {

      basketActive    = false;

      basketLockedTarget = 0.0;


      string gv = GV_BasketTargetName();

      if(GlobalVariableCheck(gv))

       GlobalVariableDel(gv);

    }


    void ActivateTargetClose(double target)

    {

      targetCloseActive    = true;

      targetCloseLockedTarget = target;

      GlobalVariableSet(GV_TargetCloseName(), target);

    }


    void DeactivateTargetClose()

    {

      targetCloseActive    = false;

      targetCloseLockedTarget = 0.0;


      string gv = GV_TargetCloseName();

      if(GlobalVariableCheck(gv))

       GlobalVariableDel(gv);

    }


    string FormatGermanNumber(double value)

    {

      string s = DoubleToString(value, 2);

      StringReplace(s, “.”, “,”);

      int commaPos = StringFind(s, “,”);

      if(commaPos > 3)

      {

       for(int i = commaPos – 3; i > 0; i -= 3)

         s = StringSubstr(s, 0, i) + “.” + StringSubstr(s, i);

      }

      return s;

    }


    void UpdateDisplay()

    {

      double realizedProfit = 0;

      double floatingProfit = 0;

      datetime startDate = 0;


      CalculateCapitalMetrics(realizedProfit, floatingProfit, startDate);


      double securedCapital = InitialVirtualCapital + realizedProfit;

      double virtualCapital = securedCapital + floatingProfit;

      double nextTarget   = CalculateNextTarget(securedCapital);

      int openCount     = GetOpenPositionsCount();


      string dateStr = (startDate > 0) ? TimeToString(startDate, TIME_DATE) : “Kein Trade”;


      string txtStart = “Start Capital (” + dateStr + “) : ” + FormatGermanNumber(InitialVirtualCapital) + ” EUR”;

      string txtCurr  = “Virtual Capital (Equity) : ” + FormatGermanNumber(virtualCapital) + ” EUR”;

      string txtTarget = “Next Capital Target (+ ” + DoubleToString(BasketTPPercent, 1) + “%) : ” + FormatGermanNumber(nextTarget) + ” EUR”;


      if(basketActive)

       txtTarget = “Basket Target LOCKED (+ ” + DoubleToString(BasketTPPercent, 1) + “%) : ” + FormatGermanNumber(basketLockedTarget) + ” EUR”;


      if(targetCloseActive)

      {

       string mode = basketActive ? “BASKET” : “SINGLE”;

       txtTarget = mode + ” TARGET CLOSE ACTIVE : ” + FormatGermanNumber(targetCloseLockedTarget) + ” EUR”;

      }

      else if(openCount == 1 && !basketActive)

      {

       txtTarget = “Single Capital Target (+ ” + DoubleToString(BasketTPPercent, 1) + “%) : ” + FormatGermanNumber(nextTarget) + ” EUR”;

      }


      CreateOrUpdateLabel(lblStart, txtStart, 35);

      CreateOrUpdateLabel(lblCurr, txtCurr, 55);

      CreateOrUpdateLabel(lblTarget, txtTarget, 75);


      ChartRedraw();

    }


    void CreateOrUpdateLabel(string name, string text, int yDist)

    {

      if(ObjectFind(0, name) < 0)

      {

       ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);

       ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_RIGHT_UPPER);

       ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_RIGHT_UPPER);

       ObjectSetInteger(0, name, OBJPROP_XDISTANCE, 15);

       ObjectSetInteger(0, name, OBJPROP_COLOR, clrBlack);

       ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 8);

       ObjectSetString(0, name, OBJPROP_FONT, “Arial”);

      }

      ObjectSetInteger(0, name, OBJPROP_YDISTANCE, yDist);

      ObjectSetString(0, name, OBJPROP_TEXT, text);

    }


    //+——————————————————————+

    //| Daten- und Log-Funktionen                    |

    //+——————————————————————+

    string SanitizeFileName(string s)

    {

      string bad = “\/:*?”<>|”;

      for(int i = 0; i < StringLen(bad); i++)

       StringReplace(s, StringSubstr(bad, i, 1), “_”);

      StringReplace(s, ” “, “_”);

      return s;

    }


    void LogTradeEvent(string line)

    {

      if(StringLen(logFileName) == 0) return;


      int handle = FileOpen(logFileName, FILE_READ|FILE_WRITE|FILE_CSV|FILE_ANSI);

      if(handle == INVALID_HANDLE)

      {

       handle = FileOpen(logFileName, FILE_WRITE|FILE_CSV|FILE_ANSI);

       if(handle == INVALID_HANDLE) return;

       FileWrite(handle, “Time;Magic;Event;Symbol;Lots;Price;SL;TP;Comment;Info;Spread;Swap”);

      }


      FileSeek(handle, 0, SEEK_END);

      FileWrite(handle, line);

      FileClose(handle);

    }


    //+——————————————————————+

    //| Handels-Kernfunktionen                      |

    //+——————————————————————+

    double RoundLotFixed(double lotsInput)

    {

      double step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);

      if(step <= 0) step = 0.1;


      double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);

      if(minLot <= 0) minLot = 0.01;


      double r = MathRound(lotsInput / step) * step;

      return NormalizeDouble(MathMax(r, minLot), 2);

    }


    bool TryBuyWithFallback(double lotsInput, double price, double sl, double tp, string comment)

    {

      ulong nowMs = GetTickCount64();


      int retryMs = RetryIntervalMs;

      if(retryMs < 0) retryMs = 0;


      if(lastEntryAttemptMs > 0 && (nowMs – lastEntryAttemptMs) < (ulong)retryMs)

       return false;


      lastEntryAttemptMs = nowMs;


      double tryLots = RoundLotFixed(lotsInput);

      double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

      double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);


      if(ask <= 0 || bid <= 0)

       return false;


      double spreadPoints = (ask – bid) / _Point;

      if(spreadPoints > MaxSpreadPoints)

       return false;


      trade.SetDeviationInPoints(MaxSlippagePoints);

      ResetLastError();


      bool requestOk = trade.Buy(tryLots, _Symbol, ask, sl, tp, comment);


      if(requestOk && IsTradeRetcodeAccepted())

      {

       LogTradeEvent(TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS) + “;” +

              (string)Magic + “;ORDER_OK;” + _Symbol + “;” +

              DoubleToString(tryLots, 2) + “;” +

              DoubleToString(ask, _Digits) + “;” +

              DoubleToString(sl, _Digits) + “;” +

              DoubleToString(tp, _Digits) + “;” +

              TradeComment + “;” + TradeResultText() + “;” +

              DoubleToString(spreadPoints, 1) + “;0”);

       return true;

      }


      Print(“D308 BUY fehlgeschlagen/abgelehnt. RequestOK=”, requestOk,

         “, “, TradeResultText(),

         “, LastError=”, GetLastError());


      return false;

    }


    //+——————————————————————+

    //| Filter-Funktionen                        |

    //+——————————————————————+

    bool IsHoliday(MqlDateTime &dt)

    {

      string date_str = StringFormat(“%02d.%02d”, dt.day, dt.mon);

      if(StringFind(InpHolidays, date_str) >= 0) return true;

      return false;

    }


    bool IsMonthBlocked(int m)

    {

      if(m == BlockMonth1 || m == BlockMonth2 || m == BlockMonth3) return true;

      if(BlockMonth4 != 0 && m == BlockMonth4) return true;

      return false;

    }


    bool IsWeekdayAllowed(int w)

    {

      if(w == 1 && InpTradeMonday)  return true;

      if(w == 2 && InpTradeTuesday)  return true;

      if(w == 3 && InpTradeWednesday) return true;

      if(w == 4 && InpTradeThursday) return true;

      if(w == 5 && InpTradeFriday)  return true;

      return false;

    }


    bool IsExitWeekdayAllowed(int w)

    {

      if(w == 1 && InpExitMonday)  return true;

      if(w == 2 && InpExitTuesday)  return true;

      if(w == 3 && InpExitWednesday) return true;

      if(w == 4 && InpExitThursday) return true;

      if(w == 5 && InpExitFriday)  return true;

      return false;

    }


    //+——————————————————————+

    //| Zeit-Management für den Ausstieg des Einzelläufers        |

    //+——————————————————————+

    datetime CalculateNextExit(datetime fromTime)

    {

      MqlDateTime dt;

      TimeToStruct(fromTime, dt);


      dt.hour = InpExitHour;

      dt.min = InpExitMinute;

      dt.sec = 0;


      datetime target = StructToTime(dt);


      while(target <= fromTime || !IsExitWeekdayAllowed(dt.day_of_week))

      {

       target += 86400;

       TimeToStruct(target, dt);

       dt.hour = InpExitHour;

       dt.min = InpExitMinute;

       dt.sec = 0;

       target = StructToTime(dt);

      }


      return target;

    }


    void RegisterAllOpenPositionsTargets()

    {

      if(!InpExitEnabled) return;


      for(int i = PositionsTotal() – 1; i >= 0; i–)

      {

       if(posInfo.SelectByIndex(i) && posInfo.Magic() == Magic && posInfo.Symbol() == _Symbol)

       {

         ulong ticket = posInfo.Ticket();

         if(!GlobalVariableCheck(GV_TargetName(ticket)))

         {

          datetime target = CalculateNextExit((datetime)posInfo.Time());

          GlobalVariableSet(GV_TargetName(ticket), (double)target);

          GlobalVariableSet(GV_NextName(ticket), (double)target);

         }

       }

      }

    }


    //+——————————————————————+

    //| Zeit-Ausstieg                           |

    //+——————————————————————+

    void CheckAndClosePositions()

    {

      if(!InpExitEnabled) return;


      if(basketActive || targetCloseActive) return;


      if(GetOpenPositionsCount() != 1) return;


      for(int i = PositionsTotal() – 1; i >= 0; i–)

      {

       if(posInfo.SelectByIndex(i) && posInfo.Magic() == Magic && posInfo.Symbol() == _Symbol)

       {

         ulong ticket = posInfo.Ticket();

         string gvT = GV_TargetName(ticket);

         string gvN = GV_NextName(ticket);


         if(!GlobalVariableCheck(gvN)) continue;

         if(TimeCurrent() < (datetime)GlobalVariableGet(gvN)) continue;


         double currentProfit = posInfo.Profit() + posInfo.Swap() + posInfo.Commission();

         if(currentProfit <= 0.0) continue;


         if(ClosePositionVerified(ticket))

         {

          if(GlobalVariableCheck(gvT)) GlobalVariableDel(gvT);

          if(GlobalVariableCheck(gvN)) GlobalVariableDel(gvN);


          LogTradeEvent(TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS) + “;” +

                 (string)Magic + “;SINGLE_EXIT_SLOT_PROFIT;” + _Symbol +

                 “;0;0;0;0;” + TradeComment +

                 “;ClosedInProfit=” + DoubleToString(currentProfit, 2) + “;0;0”);

          UpdateDisplay();

         }

         else

         {

          GlobalVariableSet(gvN, (double)(TimeCurrent() + CloseRetryIntervalHours * 3600));

         }

       }

      }

    }


    //+——————————————————————+

    //| Kapital- & Basket-Berechnungen                  |

    //+——————————————————————+

    void CalculateCapitalMetrics(double &realizedProfit, double &floatingProfit, datetime &startDate)

    {

      realizedProfit = 0;

      floatingProfit = 0;

      startDate   = 0;


      if(HistorySelect(0, TimeCurrent() + 86400))

      {

       int totalDeals = HistoryDealsTotal();

       for(int i = 0; i < totalDeals; i++)

       {

         ulong ticket = HistoryDealGetTicket(i);

         if(ticket > 0)

         {

          long  dealMagic = HistoryDealGetInteger(ticket, DEAL_MAGIC);

          string dealSymbol = HistoryDealGetString(ticket, DEAL_SYMBOL);


          if(dealMagic == Magic && dealSymbol == _Symbol)

          {

            datetime dealTime = (datetime)HistoryDealGetInteger(ticket, DEAL_TIME);

            if(startDate == 0 || dealTime < startDate)

             startDate = dealTime;


            long dealEntry = HistoryDealGetInteger(ticket, DEAL_ENTRY);

            if(dealEntry == DEAL_ENTRY_OUT || dealEntry == DEAL_ENTRY_INOUT)

            {

             realizedProfit += HistoryDealGetDouble(ticket, DEAL_PROFIT)

                     + HistoryDealGetDouble(ticket, DEAL_SWAP)

                     + HistoryDealGetDouble(ticket, DEAL_COMMISSION);

            }

          }

         }

       }

      }


      int openTotal = PositionsTotal();

      for(int i = 0; i < openTotal; i++)

      {

       if(posInfo.SelectByIndex(i) && posInfo.Magic() == Magic && posInfo.Symbol() == _Symbol)

       {

         floatingProfit += posInfo.Profit() + posInfo.Swap() + posInfo.Commission();

       }

      }

    }


    double CalculateNextTarget(double securedCapital)

    {

      if(BasketTPPercent <= 0.0)

       return DBL_MAX;


      double target   = InitialVirtualCapital;

      double multiplier = 1.0 + (BasketTPPercent / 100.0);


      while(securedCapital >= target * multiplier)

       target = target * multiplier;


      return NormalizeDouble(target * multiplier, 2);

    }


    //+——————————————————————+

    //| Kapitalziel / Basket-State-Machine                |

    //+——————————————————————+

    void CheckAndCloseBasket()

    {

      double realizedProfit = 0;

      double floatingProfit = 0;

      datetime startDate = 0;


      CalculateCapitalMetrics(realizedProfit, floatingProfit, startDate);


      double securedCapital = InitialVirtualCapital + realizedProfit;

      double virtualCapital = securedCapital + floatingProfit;

      double dynamicTarget = CalculateNextTarget(securedCapital);

      int openCount     = GetOpenPositionsCount();


      if(openCount == 0)

      {

       bool hadBasket = basketActive;

       bool hadTargetClose = targetCloseActive;

       double completedTarget = targetCloseActive ? targetCloseLockedTarget : basketLockedTarget;


       if(targetCloseActive)

         DeactivateTargetClose();

       if(basketActive)

         DeactivateBasket();


       if(hadTargetClose)

       {

         LogTradeEvent(TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS) + “;” +

                (string)Magic + “;CAPITAL_TARGET_CLOSE_SUCCESS;” + _Symbol +

                “;0;0;0;0;” + TradeComment +

                “;AllPositionsClosed;Mode=” + (hadBasket ? “BASKET” : “SINGLE”) +

                “,LockedTarget=” + DoubleToString(completedTarget, 2) + “;0;0”);

       }


       if(hadBasket || hadTargetClose)

         UpdateDisplay();


       return;

      }


      if(!basketActive && openCount >= 2)

      {

       ActivateBasket(dynamicTarget);


       LogTradeEvent(TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS) + “;” +

              (string)Magic + “;BASKET_ACTIVATED;” + _Symbol +

              “;0;0;0;0;” + TradeComment +

              “;OpenPositions=” + (string)openCount +

              “,LockedTarget=” + DoubleToString(basketLockedTarget, 2) +

              “,VirtualCap=” + DoubleToString(virtualCapital, 2) + “;0;0”);


       UpdateDisplay();

      }


      double triggerTarget = basketActive ? basketLockedTarget : dynamicTarget;


      if(basketActive && triggerTarget <= 0.0)

      {

       basketLockedTarget = dynamicTarget;

       triggerTarget = dynamicTarget;

       GlobalVariableSet(GV_BasketTargetName(), basketLockedTarget);

      }


      if(!targetCloseActive && virtualCapital >= triggerTarget)

      {

       ActivateTargetClose(triggerTarget);


       string eventName = basketActive ? “BASKET_TARGET_TRIGGER” : “SINGLE_CAPITAL_TARGET_TRIGGER”;


       LogTradeEvent(TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS) + “;” +

              (string)Magic + “;” + eventName + “;” + _Symbol +

              “;0;0;0;0;” + TradeComment +

              “;OpenPositions=” + (string)openCount +

              “,VirtualCap=” + DoubleToString(virtualCapital, 2) +

              “,Target=” + DoubleToString(triggerTarget, 2) + “;0;0”);


       UpdateDisplay();

      }


      if(!targetCloseActive)

       return;


      int closedCount = 0;


      for(int i = PositionsTotal() – 1; i >= 0; i–)

      {

       if(posInfo.SelectByIndex(i) && posInfo.Magic() == Magic && posInfo.Symbol() == _Symbol)

       {

         ulong ticket = posInfo.Ticket();


         if(ClosePositionVerified(ticket))

         {

          string gvT = GV_TargetName(ticket);

          string gvN = GV_NextName(ticket);


          if(GlobalVariableCheck(gvT)) GlobalVariableDel(gvT);

          if(GlobalVariableCheck(gvN)) GlobalVariableDel(gvN);


          closedCount++;

         }

       }

      }


      int remaining = GetOpenPositionsCount();


      if(remaining == 0)

      {

       bool wasBasket = basketActive;

       double completedTarget = targetCloseLockedTarget;


       DeactivateTargetClose();

       if(basketActive)

         DeactivateBasket();


       LogTradeEvent(TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS) + “;” +

              (string)Magic + “;CAPITAL_TARGET_CLOSE_SUCCESS;” + _Symbol +

              “;0;0;0;0;” + TradeComment +

              “;AllPositionsClosed;Mode=” + (wasBasket ? “BASKET” : “SINGLE”) +

              “,LockedTarget=” + DoubleToString(completedTarget, 2) +

              “,VirtualCapAtTrigger=” + DoubleToString(virtualCapital, 2) + “;0;0”);


       UpdateDisplay();

      }

      else if(closedCount > 0)

      {

       LogTradeEvent(TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS) + “;” +

              (string)Magic + “;CAPITAL_TARGET_CLOSE_PROGRESS;” + _Symbol +

              “;0;0;0;0;” + TradeComment +

              “;ClosedNow=” + (string)closedCount +

              “,Remaining=” + (string)remaining +

              “,Mode=” + (basketActive ? “BASKET” : “SINGLE”) +

              “,LockedTarget=” + DoubleToString(targetCloseLockedTarget, 2) + “;0;0”);


       UpdateDisplay();

      }

    }


    //+——————————————————————+

    //| Init / Deinit                          |

    //+——————————————————————+

    int OnInit()

    {

      if(InitialVirtualCapital <= 0.0 ||

       BasketTPPercent <= 0.0 ||

       FixedLotSize <= 0.0 ||

       EntryWindowSeconds <= 0 ||

       RetryIntervalMs < 0 ||

       MaxSpreadPoints < 0 ||

       MaxSlippagePoints < 0)

      {

       Print(“D308: Ungültige Eingabeparameter. EA wird nicht gestartet.”);

       return(INIT_PARAMETERS_INCORRECT);

      }


      trade.SetExpertMagicNumber(Magic);

      trade.SetDeviationInPoints(MaxSlippagePoints);


      lblStart = “D113_Lbl_Start_” + (string)Magic;

      lblCurr  = “D113_Lbl_Curr_” + (string)Magic;

      lblTarget = “D113_Lbl_Target_” + (string)Magic;


      logFileName = “D113_Log_” + _Symbol + “_” + SanitizeFileName(TradeComment) + “_” + (string)Magic + “.csv”;


      string gvEntry = GV_LastEntrySlotName();

      if(GlobalVariableCheck(gvEntry))

       lastProcessedEntrySlot = (datetime)GlobalVariableGet(gvEntry);


      string gvBasket = GV_BasketTargetName();

      if(GlobalVariableCheck(gvBasket))

      {

       basketLockedTarget = GlobalVariableGet(gvBasket);

       basketActive    = (basketLockedTarget > 0.0);

      }


      string gvClose = GV_TargetCloseName();

      if(GlobalVariableCheck(gvClose))

      {

       targetCloseLockedTarget = GlobalVariableGet(gvClose);

       targetCloseActive    = (targetCloseLockedTarget > 0.0);

      }


      int openCountInit = GetOpenPositionsCount();


      if(!basketActive && openCountInit >= 2)

      {

       double rp = 0.0, fp = 0.0;

       datetime sd = 0;

       CalculateCapitalMetrics(rp, fp, sd);

       double secured = InitialVirtualCapital + rp;

       ActivateBasket(CalculateNextTarget(secured));

      }


      if(openCountInit == 0)

      {

       if(targetCloseActive) DeactivateTargetClose();

       if(basketActive)   DeactivateBasket();

      }


      RegisterAllOpenPositionsTargets();

      UpdateDisplay();

      return(INIT_SUCCEEDED);

    }


    void OnDeinit(const int reason)

    {

      ObjectDelete(0, lblStart);

      ObjectDelete(0, lblCurr);

      ObjectDelete(0, lblTarget);

    }


    //+——————————————————————+

    //| OnTick Logic                           |

    //+——————————————————————+

    void OnTick()

    {

      CheckAndCloseBasket();


      if(targetCloseActive)

       return;


      CheckAndClosePositions();


      MqlDateTime t;

      datetime evalTime = TimeCurrent();

      if(UseBerlinOffset)

       evalTime += BerlinOffsetHours * 3600;

      TimeToStruct(evalTime, t);


      if(IsHoliday(t)) return;

      if(IsMonthBlocked(t.mon)) return;

      if(!IsWeekdayAllowed(t.day_of_week)) return;


      MqlDateTime slot = t;

      slot.hour = InpEntryHour;

      slot.min = InpEntryMinute;

      slot.sec = 0;


      datetime slotStart = StructToTime(slot);

      long diff = (long)evalTime – (long)slotStart;


      if(diff >= 0 && diff <= EntryWindowSeconds && lastProcessedEntrySlot != slotStart)

      {

       int shift = 1;

       MqlDateTime dtPrev;

       TimeToStruct(iTime(_Symbol, PERIOD_D1, 1), dtPrev);

       if(dtPrev.day_of_week == 0)

         shift = 2;


       if(iLow(_Symbol, PERIOD_D1, 0) < iLow(_Symbol, PERIOD_D1, shift) ||

         iHigh(_Symbol, PERIOD_D1, 0) < iHigh(_Symbol, PERIOD_D1, shift))

       {

         if(CumulateOrders || !PositionSelectByMagic(Magic))

         {

          double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);


          double sl = 0.0;

          double tp = 0.0;


          if(StopLossPercent > 0.0)

            sl = NormalizeDouble(ask * (1.0 – StopLossPercent / 100.0), _Digits);


          if(TakeProfitPercent > 0.0)

            tp = NormalizeDouble(ask * (1.0 + TakeProfitPercent / 100.0), _Digits);


          if(TryBuyWithFallback(FixedLotSize, ask, sl, tp, TradeComment))

          {

            RegisterAllOpenPositionsTargets();

            MarkEntrySlotProcessed(slotStart);

            UpdateDisplay();

          }

         }

       }

       else

       {

         MarkEntrySlotProcessed(slotStart);

       }

      }

    }


    bool PositionSelectByMagic(long mg)

    {

      for(int i = PositionsTotal() – 1; i >= 0; i–)

      {

       if(posInfo.SelectByIndex(i) && posInfo.Magic() == mg && posInfo.Symbol() == _Symbol)

         return true;

      }

      return false;

    }

Viewing 1 post (of 1 total)
  • You must be logged in to reply to this topic.
ProRealAI ProRealAI New

Stuck on this ProBuilder code?

Describe what this topic is trying to build, in plain English, and ProRealAI writes the ProRealTime™ indicator, screener or system for you.

Available in 7 languages
Try ProRealAI

DE40 : Capital Management with a Dynamic Basket TP – Implementation


ProOrder: Automatischer Handel & Backtesting

New Reply
Author
author-avatar
JohnScher @johnscher Participant
Summary

This topic contains 1 voice and has 0 replies.

Topic Details
Forum: ProOrder: Automatischer Handel & Backtesting
Language: German
Started: 09/29/2026
Status: Active
Attachments: No files
ProRealCode ProRealCode
Loading...