mql5/Experts/_Architecture/Trade/TradeManager.mqh

155 lines
5.2 KiB
MQL5

2026-08-14 16:19:56 +02:00
//+------------------------------------------------------------------+
//| 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 <Mql5Book\TrailingStops.mqh>
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
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" );
}
}
}
}
}
}
//+------------------------------------------------------------------+