188 lines
5.0 KiB
Plaintext
188 lines
5.0 KiB
Plaintext
//+------------------------------------------------------------------+
|
|
//| TradeManager.mqh - Trade execution using CTrade class |
|
|
//| Handles buy/sell orders with SL/TP and magic number |
|
|
//+------------------------------------------------------------------+
|
|
|
|
#ifndef __TRADEMANAGER_MQH__
|
|
#define __TRADEMANAGER_MQH__
|
|
|
|
#include <Trade/Trade.mqh>
|
|
#include "Config.mqh"
|
|
#include "Logger.mqh"
|
|
#include "RiskManager.mqh"
|
|
|
|
class CTradeManager
|
|
{
|
|
private:
|
|
CTrade m_trade;
|
|
CLogger *mp_logger;
|
|
CRiskManager *mp_risk_manager;
|
|
|
|
public:
|
|
// Constructor
|
|
CTradeManager(CLogger *logger, CRiskManager *risk_manager)
|
|
{
|
|
mp_logger = logger;
|
|
mp_risk_manager = risk_manager;
|
|
|
|
// Set magic number
|
|
m_trade.SetExpertMagicNumber((ulong)g_magic_number);
|
|
|
|
// Set async/sync mode
|
|
m_trade.SetAsyncMode(false);
|
|
|
|
// Set slippage
|
|
m_trade.SetDeviationInPoints(10);
|
|
}
|
|
|
|
// Destructor
|
|
~CTradeManager()
|
|
{
|
|
}
|
|
|
|
// Open BUY trade
|
|
bool OpenBuyTrade(const string symbol, double lot)
|
|
{
|
|
if(lot <= 0)
|
|
{
|
|
if(mp_logger)
|
|
mp_logger.Error(StringFormat("Invalid lot size: %.2f", lot));
|
|
return false;
|
|
}
|
|
|
|
double ask = mp_risk_manager.GetMarketData().GetAsk();
|
|
double sl = mp_risk_manager.CalculateStopLossPrice(true);
|
|
double tp = mp_risk_manager.CalculateTakeProfitPrice(true);
|
|
|
|
if(mp_logger && g_debug_mode)
|
|
mp_logger.Info(StringFormat("Opening BUY: lot=%.2f, SL=%.5f, TP=%.5f", lot, sl, tp));
|
|
|
|
if(!m_trade.Buy(lot, symbol, ask, sl, tp))
|
|
{
|
|
if(mp_logger)
|
|
{
|
|
mp_logger.Error(StringFormat("Buy trade failed. Result code: %d, Error: %s",
|
|
m_trade.ResultRetcode(), m_trade.ResultRetcodeDescription()));
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if(mp_logger)
|
|
{
|
|
mp_logger.Info(StringFormat("Buy trade opened. Ticket: %I64d, Volume: %.2f",
|
|
m_trade.ResultOrder(), lot));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Open SELL trade
|
|
bool OpenSellTrade(const string symbol, double lot)
|
|
{
|
|
if(lot <= 0)
|
|
{
|
|
if(mp_logger)
|
|
mp_logger.Error(StringFormat("Invalid lot size: %.2f", lot));
|
|
return false;
|
|
}
|
|
|
|
double bid = mp_risk_manager.GetMarketData().GetBid();
|
|
double sl = mp_risk_manager.CalculateStopLossPrice(false);
|
|
double tp = mp_risk_manager.CalculateTakeProfitPrice(false);
|
|
|
|
if(mp_logger && g_debug_mode)
|
|
mp_logger.Info(StringFormat("Opening SELL: lot=%.2f, SL=%.5f, TP=%.5f", lot, sl, tp));
|
|
|
|
if(!m_trade.Sell(lot, symbol, bid, sl, tp))
|
|
{
|
|
if(mp_logger)
|
|
{
|
|
mp_logger.Error(StringFormat("Sell trade failed. Result code: %d, Error: %s",
|
|
m_trade.ResultRetcode(), m_trade.ResultRetcodeDescription()));
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if(mp_logger)
|
|
{
|
|
mp_logger.Info(StringFormat("Sell trade opened. Ticket: %I64d, Volume: %.2f",
|
|
m_trade.ResultOrder(), lot));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Close position by ticket
|
|
bool ClosePosition(ulong ticket)
|
|
{
|
|
if(ticket == 0)
|
|
return false;
|
|
|
|
if(!PositionSelectByTicket(ticket))
|
|
return false;
|
|
|
|
double volume = PositionGetDouble(POSITION_VOLUME);
|
|
string symbol = PositionGetString(POSITION_SYMBOL);
|
|
|
|
if(mp_logger && g_debug_mode)
|
|
mp_logger.Info(StringFormat("Closing position ticket %I64d, volume %.2f", ticket, volume));
|
|
|
|
if(!m_trade.PositionClose(ticket))
|
|
{
|
|
if(mp_logger)
|
|
{
|
|
mp_logger.Error(StringFormat("Close position failed. Ticket: %I64d, Result: %d",
|
|
ticket, m_trade.ResultRetcode()));
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if(mp_logger)
|
|
mp_logger.Info(StringFormat("Position closed. Ticket: %I64d", ticket));
|
|
|
|
return true;
|
|
}
|
|
|
|
// Modify position SL and/or TP
|
|
bool ModifyPosition(ulong ticket, double sl, double tp)
|
|
{
|
|
if(ticket == 0)
|
|
return false;
|
|
|
|
if(!PositionSelectByTicket(ticket))
|
|
return false;
|
|
|
|
if(mp_logger && g_debug_mode)
|
|
mp_logger.Info(StringFormat("Modifying position %I64d: SL=%.5f, TP=%.5f", ticket, sl, tp));
|
|
|
|
if(!m_trade.PositionModify(ticket, sl, tp))
|
|
{
|
|
if(mp_logger)
|
|
{
|
|
mp_logger.Error(StringFormat("Position modify failed. Ticket: %I64d, Result: %d",
|
|
ticket, m_trade.ResultRetcode()));
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if(mp_logger && g_debug_mode)
|
|
mp_logger.Info(StringFormat("Position modified. Ticket: %I64d", ticket));
|
|
|
|
return true;
|
|
}
|
|
|
|
// Get last result code
|
|
uint GetResultRetcode() const
|
|
{
|
|
return m_trade.ResultRetcode();
|
|
}
|
|
|
|
// Get CTrade instance
|
|
CTrade* GetTradeObject()
|
|
{
|
|
return &m_trade;
|
|
}
|
|
};
|
|
|
|
#endif //__TRADEMANAGER_MQH__
|