//+------------------------------------------------------------------+ //| ManagePositions.mqh | //| Jules | //+------------------------------------------------------------------+ #property copyright "Jules" #property strict #include #include #include class CPositionManager { private: CPositionInfo m_positionInfo; CSymbolInfo m_symbolInfo; CTrade* m_trade; // Pointer to external CTrade public: void Init(CTrade* tradeObj) { m_trade = tradeObj; } void Manage(long magic, string symbol, bool useBreakEven, double breakEvenTriggerPips, double breakEvenOffsetPips, bool useTrail, double trailingStopStartPips, double trailingStopDistancePips) { if(m_trade == NULL) return; if(!m_symbolInfo.Name(symbol)) return; if(!m_symbolInfo.RefreshRates()) return; double point = m_symbolInfo.Point(); int digits = m_symbolInfo.Digits(); // Calculate point value for pips (assuming standard 1 pip = 10 points) // For JPY pairs or others, usually it's consistent if we use Point * 10 for "Pip" // But let's use the standard "10 points = 1 pip" convention. double pipSize = point * 10.0; for(int i = PositionsTotal() - 1; i >= 0; i--) { if(!m_positionInfo.SelectByIndex(i)) continue; if(m_positionInfo.Magic() != magic) continue; if(m_positionInfo.Symbol() != symbol) continue; double openPrice = m_positionInfo.PriceOpen(); double currentSL = m_positionInfo.StopLoss(); double currentTP = m_positionInfo.TakeProfit(); ulong ticket = m_positionInfo.Ticket(); double newSL = currentSL; double profitPips = 0.0; if(m_positionInfo.PositionType() == POSITION_TYPE_BUY) { double bid = m_symbolInfo.Bid(); profitPips = (bid - openPrice) / pipSize; // Break Even if(useBreakEven && profitPips >= breakEvenTriggerPips) { double beLevel = openPrice + (breakEvenOffsetPips * pipSize); // Move SL to BE if current SL is below BE if(currentSL < beLevel || currentSL == 0) newSL = beLevel; } // Trailing if(useTrail && profitPips >= trailingStopStartPips) { double trailLevel = bid - (trailingStopDistancePips * pipSize); // Move SL up if trail level is higher than current SL if(trailLevel > newSL || newSL == 0) newSL = trailLevel; } } else if(m_positionInfo.PositionType() == POSITION_TYPE_SELL) { double ask = m_symbolInfo.Ask(); profitPips = (openPrice - ask) / pipSize; // Break Even if(useBreakEven && profitPips >= breakEvenTriggerPips) { double beLevel = openPrice - (breakEvenOffsetPips * pipSize); // Move SL to BE if current SL is above BE if(currentSL > beLevel || currentSL == 0) newSL = beLevel; } // Trailing if(useTrail && profitPips >= trailingStopStartPips) { double trailLevel = ask + (trailingStopDistancePips * pipSize); // Move SL down if trail level is lower than current SL if(trailLevel < newSL || newSL == 0) newSL = trailLevel; } } if(MathAbs(newSL - currentSL) > point) { // Normalize newSL = NormalizeDouble(newSL, digits); // Check stops level double stopLevel = (double)SymbolInfoInteger(symbol, SYMBOL_TRADE_STOPS_LEVEL) * point; bool valid = true; if(m_positionInfo.PositionType() == POSITION_TYPE_BUY) { if(m_symbolInfo.Bid() - newSL < stopLevel) valid = false; } else { if(newSL - m_symbolInfo.Ask() < stopLevel) valid = false; } if(valid) { if(m_trade->PositionModify(ticket, newSL, currentTP)) { Print("ManagePositions: Position #", ticket, " SL moved to ", newSL); } } } } } };