//+------------------------------------------------------------------+ //| Utils.mqh | //| Copyright 2026, MasterOfPuppets | //| https://forge.mql5.io/masterofpuppets/mql5 | //+------------------------------------------------------------------+ #ifndef MASTER_OF_PUPPETS_LIB_UTILS_MQH #define MASTER_OF_PUPPETS_LIB_UTILS_MQH #include #include #include #property copyright "Copyright 2026, MasterOfPuppets" #property link "https://forge.mql5.io/masterofpuppets/mql5" //+------------------------------------------------------------------+ //| Positions initialization function | //+------------------------------------------------------------------+ void InitPositions(CPositionInfo &srcPositionInfo) { ulong allPositionsTickets[]; int positionsTotal = PositionsTotal(); Print("positionsTotal: ", positionsTotal); ArrayFree(allPositionsTickets); ArrayResize(allPositionsTickets, positionsTotal); for(int i = 0; i < positionsTotal; i++) { if(srcPositionInfo.SelectByIndex(i)) { allPositionsTickets[i] = srcPositionInfo.Ticket(); } } ArrayPrint(allPositionsTickets); } //+------------------------------------------------------------------+ //| Is key mapping correct function | //+------------------------------------------------------------------+ template bool IsKeyMappingCorrect(Actions &actionsObject) { int actionKeys[]; actionsObject.GetActionKeys(actionKeys); string actionNames[]; actionsObject.GetActionNames(actionNames); DuplicateResult duplicateResults[]; DuplicateFinder::Find(actionKeys, duplicateResults); if(duplicateResults.Size() == 0) { return true; } string error; for(uint i = 0; i < duplicateResults.Size(); i++) { string mappedActionNames; for(uint j = 0; j < duplicateResults[i].indices.Size(); j++) { if(j > 0) { mappedActionNames += ", "; } mappedActionNames += actionNames[duplicateResults[i].indices[j]]; } error += StringFormat("Error: duplicated key [%c] for %s\n", (uchar) duplicateResults[i].value, mappedActionNames); } Alert(error); return false; } //+------------------------------------------------------------------+ //| Is standard deal reason function | //+------------------------------------------------------------------+ bool IsStandardDealReason(const int dealReason) { switch(dealReason) { case DEAL_REASON_CLIENT: case DEAL_REASON_EXPERT: case DEAL_REASON_MOBILE: case DEAL_REASON_SL: case DEAL_REASON_TP: case DEAL_REASON_WEB: return true; } return false; } //+------------------------------------------------------------------+ //| Is zero function | //+------------------------------------------------------------------+ bool IsZero(const double value) { return MathAbs(value) < DBL_EPSILON; } //+------------------------------------------------------------------+ //| Play sound file function | //+------------------------------------------------------------------+ void PlaySoundFile(const bool soundEnabled, const string soundFileName) { if(soundEnabled) { PlaySound(soundFileName); } } //+------------------------------------------------------------------+ //| Trailing stop function | //+------------------------------------------------------------------+ //OnTick() TrailingStep void TrailingStop(const int distance) { double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT); double trailingStep = distance * point; for(int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(PositionSelectByTicket(ticket)) { double openPrice = PositionGetDouble(POSITION_PRICE_OPEN); double currentSL = PositionGetDouble(POSITION_SL); double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); // Для покупок (Buy) if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { if(bid - openPrice > trailingStep) // Проверяем, в прибыли ли мы { if(currentSL < bid - trailingStep) { MqlTradeRequest request = {}; MqlTradeResult result = {}; request.action = TRADE_ACTION_SLTP; request.position = ticket; request.sl = NormalizeDouble(bid - trailingStep, _Digits); request.tp = PositionGetDouble(POSITION_TP); if(OrderSend(request, result)) { }; } } } // Для продаж (Sell) else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) { if(openPrice - ask > trailingStep) { if(currentSL > ask + trailingStep || currentSL == 0) { MqlTradeRequest request = {}; MqlTradeResult result = {}; request.action = TRADE_ACTION_SLTP; request.position = ticket; request.sl = NormalizeDouble(ask + trailingStep, _Digits); request.tp = PositionGetDouble(POSITION_TP); if(OrderSend(request, result)) { }; } } } } } } #endif //+------------------------------------------------------------------+