//+------------------------------------------------------------------+ //| TradeManager.mqh | //| Copyright 2025, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #include "../Configs/EAConfig.mqh" #include "../Market/DataManager.mqh" #include "TradeExecutor.mqh" #include "../Events/Events/TradingEvents.mqh" #include //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class TradeManager final: public IEventListener { private: EventBus* m_bus; ITradeExecutor* m_executor; CTrailing m_trail; EAConfig configs; CPositions pos; SymbolConfig findSymbol(string symbol) { for(int i = 0; i < configs.tfConfigs.Size(); i++) { SymbolConfig data = configs.tfConfigs.At(i); if(data.symbol == symbol) return data; } SymbolConfig t; return t; } public: TradeManager() {} ~TradeManager() {} double GetPoint(string symbol) { return SymbolInfoDouble(symbol, SYMBOL_POINT); } void TrailingAndBreakeven(string symbol); void Initialize(EventBus * bus, ITradeExecutor * executor, EAConfig & m_configs) { m_bus = bus; m_executor = executor; configs = m_configs; } virtual void OnEvent(AbstractEvent * event) override { if(event.GetType() == EXECUTE_MARKET_ORDER) { ExecuteMarketOrderEvent* e = (ExecuteMarketOrderEvent*)event; MarketOrderRequest req; req.symbol = e.GetSymbolName(); req.direction = e.GetDirection(); req.volume = e.GetVolume(); req.sl = e.GetSL(); req.tp = e.GetTP(); req.comment = e.GetComment(); req.magic = configs.magicNumber; req.price = e.GetPrice(); ulong ticket = m_executor.PlaceMarketOrder(req); if(ticket > 0) { PositionOpenedEvent* dpos = new PositionOpenedEvent(ticket, req.symbol, req.direction, req.volume, req.price, req.sl, req.tp, TimeCurrent()); m_bus.Push(dpos); } } else if(event.GetType() == EXECUTE_PENDING_ORDER) { ExecutePendingOrderEvent* pend = (ExecutePendingOrderEvent*)event; PendingOrderRequest req; req.symbol = pend.GetSymbolName(); req.type = pend.GetOrderType(); req.volume = pend.GetVolume(); req.price = pend.GetPrice(); req.stoplimit = pend.GetStopLimit(); req.sl = pend.GetSL(); req.tp = pend.GetTP(); req.expiration = pend.GetExpiration(); req.comment = pend.GetComment(); req.magic = configs.magicNumber; ulong ticket = m_executor.PlacePendingOrder(req); if(ticket > 0) { PendingOrderPlacedEvent* placed = new PendingOrderPlacedEvent( ticket, req.symbol, req.type, req.volume, req.price, req.sl, req.tp, req.expiration, req.comment); m_bus.Push(placed); } } else if(event.GetType() == NEW_BAR) { TrailingAndBreakeven(event.GetSymbolName()); } } }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void TradeManager::TrailingAndBreakeven(string symbol) { ulong tickets[]; pos.GetTickets(configs.magicNumber, tickets); //Print(symbol, ": ", ArraySize(tickets)); SymbolConfig c = findSymbol(symbol); for(int i = 0; i < ArraySize(tickets); i++) { if(c.rmConfigs.UseTrailingStop) m_trail.TrailingStop(tickets[i], c.rmConfigs.TrailingStop, c.rmConfigs.MinimumProfit, c.rmConfigs.Step); if(c.rmConfigs.UseBreakEven) m_trail.BreakEven(tickets[i], c.rmConfigs.BreakEvenProfit, c.rmConfigs.LockProfit); if(c.rmConfigs.UseAutoClose) { if(PositionSelectByTicket(tickets[i])) { long open_time = PositionGetInteger(POSITION_TIME); datetime current_time = TimeCurrent(); int bar_count = Bars(symbol, c.tradeTimeframe, open_time, current_time); // Print(symbol, ": ", bar_count); if(bar_count >= c.rmConfigs.tradeDuration) { Print(symbol, ":Close ", bar_count); if(m_executor.ClosePosition(tickets[i])) { Print( "Closed" ); } } } } } } //+------------------------------------------------------------------+