Split HIT EA into entry and position manager
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
#ifndef HIT_POSITION_LIFECYCLE_MANAGER_MQH
|
||||
#define HIT_POSITION_LIFECYCLE_MANAGER_MQH
|
||||
|
||||
#include <Trade/Trade.mqh>
|
||||
|
||||
// Ticket-based position lifecycle manager for hedging accounts.
|
||||
class CHITPositionLifecycleManager
|
||||
{
|
||||
private:
|
||||
string m_symbol;
|
||||
ulong m_magic;
|
||||
ulong m_deviation_points;
|
||||
int m_close_after_seconds;
|
||||
CTrade m_trade;
|
||||
|
||||
public:
|
||||
CHITPositionLifecycleManager()
|
||||
{
|
||||
m_symbol = _Symbol;
|
||||
m_magic = 0;
|
||||
m_deviation_points = 10;
|
||||
m_close_after_seconds = 0;
|
||||
}
|
||||
|
||||
bool Init(const string symbol,
|
||||
const ulong magic,
|
||||
const ulong deviation_points,
|
||||
const int close_after_seconds)
|
||||
{
|
||||
m_symbol = symbol;
|
||||
m_magic = magic;
|
||||
m_deviation_points = deviation_points;
|
||||
m_close_after_seconds = close_after_seconds;
|
||||
|
||||
if(m_symbol == "")
|
||||
{
|
||||
Print("HITPositionLifecycleManager init failed: symbol is empty.");
|
||||
return false;
|
||||
}
|
||||
|
||||
ResetLastError();
|
||||
if(!SymbolSelect(m_symbol, true))
|
||||
{
|
||||
Print("HITPositionLifecycleManager init failed: symbol=", m_symbol,
|
||||
" err=", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
m_trade.SetExpertMagicNumber(m_magic);
|
||||
m_trade.SetDeviationInPoints((int)m_deviation_points);
|
||||
m_trade.SetTypeFillingBySymbol(m_symbol);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SetCloseAfterSeconds(const int close_after_seconds)
|
||||
{
|
||||
m_close_after_seconds = close_after_seconds;
|
||||
}
|
||||
|
||||
int CountTargetPositions()
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for(int i = PositionsTotal() - 1; i >= 0; --i)
|
||||
{
|
||||
const ulong ticket = PositionGetTicket(i);
|
||||
if(ticket == 0)
|
||||
continue;
|
||||
if(!PositionSelectByTicket(ticket))
|
||||
continue;
|
||||
if(!IsTargetSelectedPosition())
|
||||
continue;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
bool CloseExpiredPositions()
|
||||
{
|
||||
if(m_close_after_seconds <= 0)
|
||||
return false;
|
||||
|
||||
bool result = false;
|
||||
const datetime current_time = TimeCurrent();
|
||||
|
||||
for(int i = PositionsTotal() - 1; i >= 0; --i)
|
||||
{
|
||||
const ulong ticket = PositionGetTicket(i);
|
||||
if(ticket == 0)
|
||||
continue;
|
||||
|
||||
ResetLastError();
|
||||
if(!PositionSelectByTicket(ticket))
|
||||
{
|
||||
Print("HITPositionLifecycleManager select failed: ticket=", ticket,
|
||||
" err=", GetLastError());
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!IsTargetSelectedPosition())
|
||||
continue;
|
||||
|
||||
const datetime entry_time = (datetime)PositionGetInteger(POSITION_TIME);
|
||||
if(entry_time <= 0)
|
||||
continue;
|
||||
|
||||
if(current_time - entry_time < m_close_after_seconds)
|
||||
continue;
|
||||
|
||||
if(CloseSelectedPosition(ticket, "time limit"))
|
||||
result = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
bool IsTargetSelectedPosition()
|
||||
{
|
||||
if(PositionGetString(POSITION_SYMBOL) != m_symbol)
|
||||
return false;
|
||||
if((ulong)PositionGetInteger(POSITION_MAGIC) != m_magic)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
string PositionTypeText(const ENUM_POSITION_TYPE type)
|
||||
{
|
||||
if(type == POSITION_TYPE_BUY)
|
||||
return "BUY";
|
||||
if(type == POSITION_TYPE_SELL)
|
||||
return "SELL";
|
||||
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
bool CloseSelectedPosition(const ulong ticket,
|
||||
const string reason)
|
||||
{
|
||||
const ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
const double volume = PositionGetDouble(POSITION_VOLUME);
|
||||
|
||||
ResetLastError();
|
||||
if(!m_trade.PositionClose(ticket, m_deviation_points))
|
||||
{
|
||||
Print("HITPositionLifecycleManager close failed: ticket=", ticket,
|
||||
" symbol=", m_symbol,
|
||||
" magic=", m_magic,
|
||||
" type=", PositionTypeText(type),
|
||||
" volume=", DoubleToString(volume, 2),
|
||||
" reason=", reason,
|
||||
" retcode=", m_trade.ResultRetcode(),
|
||||
" err=", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
Print("HITPositionLifecycleManager closed position: ticket=", ticket,
|
||||
" symbol=", m_symbol,
|
||||
" magic=", m_magic,
|
||||
" type=", PositionTypeText(type),
|
||||
" volume=", DoubleToString(volume, 2),
|
||||
" reason=", reason,
|
||||
" retcode=", m_trade.ResultRetcode());
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user