Finalize EA architecture before strategy development
This commit is contained in:
+43
-49
@@ -1,6 +1,6 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| TradeManager.mqh - Trade execution using CTrade class |
|
||||
//| Handles buy/sell orders with SL/TP and magic number |
|
||||
//| Handles buy/sell orders with explicit SL/TP and risk controls |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
#ifndef __TRADEMANAGER_MQH__
|
||||
@@ -19,100 +19,105 @@ private:
|
||||
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)
|
||||
bool OpenBuyTrade(const string symbol, double lot, double sl, double tp, double setupEntryPrice = 0.0)
|
||||
{
|
||||
if(lot <= 0)
|
||||
if(lot <= 0.0)
|
||||
{
|
||||
if(mp_logger)
|
||||
mp_logger.Error(StringFormat("Invalid lot size: %.2f", lot));
|
||||
return false;
|
||||
}
|
||||
|
||||
// TP-less trades are intentionally unsupported until TradeSetup has an
|
||||
// explicit allowNoTakeProfit field; do not infer that from tp = 0.
|
||||
if(sl <= 0.0 || tp <= 0.0)
|
||||
{
|
||||
if(mp_logger)
|
||||
mp_logger.Error("Invalid SL or TP provided for BUY order");
|
||||
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));
|
||||
{
|
||||
double sl_distance = MathAbs(ask - sl);
|
||||
double tp_distance = MathAbs(tp - ask);
|
||||
double setup_diff = (setupEntryPrice > 0.0) ? MathAbs(setupEntryPrice - ask) : 0.0;
|
||||
string setup_info = (setupEntryPrice > 0.0) ? StringFormat("setupEntry=%.5f, execEntry=%.5f, diff=%.5f, ", setupEntryPrice, ask, setup_diff) : "execEntry=" + DoubleToString(ask, 5) + ", ";
|
||||
mp_logger.Info(StringFormat("Opening BUY: %s lot=%.2f, SL=%.5f, TP=%.5f, SL dist=%.5f, TP dist=%.5f",
|
||||
setup_info, lot, sl, tp, sl_distance, tp_distance));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
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)
|
||||
bool OpenSellTrade(const string symbol, double lot, double sl, double tp, double setupEntryPrice = 0.0)
|
||||
{
|
||||
if(lot <= 0)
|
||||
if(lot <= 0.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);
|
||||
// TP-less trades are intentionally unsupported until TradeSetup has an
|
||||
// explicit allowNoTakeProfit field; do not infer that from tp = 0.
|
||||
if(sl <= 0.0 || tp <= 0.0)
|
||||
{
|
||||
if(mp_logger)
|
||||
mp_logger.Error("Invalid SL or TP provided for SELL order");
|
||||
return false;
|
||||
}
|
||||
|
||||
double bid = mp_risk_manager.GetMarketData().GetBid();
|
||||
if(mp_logger && g_debug_mode)
|
||||
mp_logger.Info(StringFormat("Opening SELL: lot=%.2f, SL=%.5f, TP=%.5f", lot, sl, tp));
|
||||
{
|
||||
double sl_distance = MathAbs(sl - bid);
|
||||
double tp_distance = MathAbs(bid - tp);
|
||||
double setup_diff = (setupEntryPrice > 0.0) ? MathAbs(setupEntryPrice - bid) : 0.0;
|
||||
string setup_info = (setupEntryPrice > 0.0) ? StringFormat("setupEntry=%.5f, execEntry=%.5f, diff=%.5f, ", setupEntryPrice, bid, setup_diff) : "execEntry=" + DoubleToString(bid, 5) + ", ";
|
||||
mp_logger.Info(StringFormat("Opening SELL: %s lot=%.2f, SL=%.5f, TP=%.5f, SL dist=%.5f, TP dist=%.5f",
|
||||
setup_info, lot, sl, tp, sl_distance, tp_distance));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
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)
|
||||
@@ -122,18 +127,13 @@ public:
|
||||
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()));
|
||||
}
|
||||
mp_logger.Error(StringFormat("Close position failed. Ticket: %I64d, Result: %d", ticket, m_trade.ResultRetcode()));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -143,7 +143,6 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
// Modify position SL and/or TP
|
||||
bool ModifyPosition(ulong ticket, double sl, double tp)
|
||||
{
|
||||
if(ticket == 0)
|
||||
@@ -158,10 +157,7 @@ public:
|
||||
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()));
|
||||
}
|
||||
mp_logger.Error(StringFormat("Position modify failed. Ticket: %I64d, Result: %d", ticket, m_trade.ResultRetcode()));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -171,13 +167,11 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get last result code
|
||||
uint GetResultRetcode() const
|
||||
{
|
||||
return m_trade.ResultRetcode();
|
||||
}
|
||||
|
||||
// Get CTrade instance
|
||||
CTrade* GetTradeObject()
|
||||
{
|
||||
return &m_trade;
|
||||
|
||||
Reference in New Issue
Block a user