Warrior_EA/Expert/ExpertCustom.mqh
super.admin 0a527b0cf9 convert
2025-05-30 16:35:54 +02:00

351 lines
27 KiB
MQL5

//+------------------------------------------------------------------+
//| Expert.mqh |
//| Copyright 2000-2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#include <Expert\Expert.mqh>
#include "ExpertSignalCustom.mqh"
//+------------------------------------------------------------------+
//| Class CExpert. |
//| Purpose: Base class expert advisor. |
//| Derives from class CExpert. |
//+------------------------------------------------------------------+
class CExpertCustom : public CExpert
{
protected:
CExpertSignalCustom* GetCustomSignal()
{
return dynamic_cast<CExpertSignalCustom*>(m_signal);
}
bool CloseAndDeleteAllForSymbol(void);
public:
CExpertCustom(void);
~CExpertCustom(void);
//--- event handlers
virtual void OnTick(void) override;
virtual void OnTimer(void) override;
virtual void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) override;
//--- initialization trading objects
virtual bool InitSignal(CExpertSignal *signal = NULL) override;
//--- methods of creating the indicator and timeseries
virtual bool SetPriceSeries(CiOpen *open, CiHigh *high, CiLow *low, CiClose *close) override;
virtual bool SetOtherSeries(CiSpread *spread, CiTime *time, CiTickVolume *tick_volume, CiRealVolume *real_volume) override;
//--- initialization trading objects
virtual bool InitTrade(ulong magic, CExpertTrade *trade = NULL) override;
protected:
//--- refreshing
virtual bool Refresh(void) override;
//--- processing (main method)
virtual bool Processing(void) override;
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CExpertCustom::CExpertCustom(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CExpertCustom::~CExpertCustom(void)
{
}
//+------------------------------------------------------------------+
//| Setting pointers of price timeseries. |
//+------------------------------------------------------------------+
bool CExpertCustom::SetPriceSeries(CiOpen *open, CiHigh *high, CiLow *low, CiClose *close) override
{
//--- check the initialization phase
if(m_init_phase != INIT_PHASE_VALIDATION)
{
//Print(__FUNCTION__+": changing of timeseries is forbidden");
return(false);
}
//--- check pointers
if((IS_OPEN_SERIES_USAGE && open == NULL) ||
(IS_HIGH_SERIES_USAGE && high == NULL) ||
(IS_LOW_SERIES_USAGE && low == NULL) ||
(IS_CLOSE_SERIES_USAGE && close == NULL))
{
Print(__FUNCTION__ + ": NULL pointer");
return(false);
}
m_open = open;
m_high = high;
m_low = low;
m_close = close;
//--- ok
return(true);
}
//+------------------------------------------------------------------+
//| Setting pointers of other timeseries. |
//+------------------------------------------------------------------+
bool CExpertCustom::SetOtherSeries(CiSpread *spread, CiTime *time, CiTickVolume *tick_volume, CiRealVolume *real_volume) override
{
//--- check the initialization phase
if(m_init_phase != INIT_PHASE_VALIDATION)
{
//Print(__FUNCTION__+": changing of timeseries is forbidden");
return(false);
}
//--- check pointers
if((IS_SPREAD_SERIES_USAGE && spread == NULL) ||
(IS_TIME_SERIES_USAGE && time == NULL) ||
(IS_TICK_VOLUME_SERIES_USAGE && tick_volume == NULL) ||
(IS_REAL_VOLUME_SERIES_USAGE && real_volume == NULL))
{
Print(__FUNCTION__ + ": NULL pointer");
return(false);
}
m_spread = spread;
m_time = time;
m_tick_volume = tick_volume;
m_real_volume = real_volume;
//--- ok
return(true);
}
//+------------------------------------------------------------------+
//| Initialization signal object |
//+------------------------------------------------------------------+
bool CExpertCustom::InitSignal(CExpertSignal *signal)
{
if(m_signal != NULL)
delete m_signal;
//---
if(signal == NULL)
{
if((m_signal = new CExpertSignalCustom) == NULL)
return(false);
}
else
m_signal = signal;
//--- initializing signal object
if(!m_signal.Init(GetPointer(m_symbol), m_period, m_adjusted_point))
return(false);
m_signal.EveryTick(m_every_tick);
m_signal.Magic(m_magic);
//--- ok
return(true);
}
//+------------------------------------------------------------------+
//| Refreshing data for processing |
//+------------------------------------------------------------------+
bool CExpertCustom::Refresh(void)
{
MqlDateTime time;
//--- refresh rates
if(!m_symbol.RefreshRates())
return(false);
//--- check need processing
TimeToStruct(m_symbol.Time(), time);
if(m_period_flags != WRONG_VALUE && m_period_flags != 0)
if((m_period_flags & TimeframesFlags(time)) == 0)
return(false);
m_last_tick_time = time;
//--- refresh indicators
m_indicators.Refresh();
//--- ok
return(true);
}
//+------------------------------------------------------------------+
//| Main function |
//+------------------------------------------------------------------+
bool CExpertCustom::Processing(void)
{
//--- calculate signal direction once
//Print("Setting direction...");
m_signal.SetDirection();
//Print("Done.");
//--- check if open positions
if(SelectPosition())
{
//--- open position is available
//--- check the possibility of reverse the position
if(CheckReverse())
return(true);
//--- check the possibility of closing the position/delete pending orders
if(!CheckClose())
{
//--- check the possibility of modifying the position
if(CheckTrailingStop())
return(true);
//--- return without operations
return(false);
}
}
//--- check if plased pending orders
int total = OrdersTotal();
if(total != 0)
{
for(int i = total - 1; i >= 0; i--)
{
m_order.SelectByIndex(i);
if(m_order.Symbol() != m_symbol.Name())
continue;
if(m_order.OrderType() == ORDER_TYPE_BUY_LIMIT || m_order.OrderType() == ORDER_TYPE_BUY_STOP)
{
//--- check the ability to delete a pending order to buy
if(CheckDeleteOrderLong())
return(true);
//--- check the possibility of modifying a pending order to buy
if(CheckTrailingOrderLong())
return(true);
}
else
{
//--- check the ability to delete a pending order to sell
if(CheckDeleteOrderShort())
return(true);
//--- check the possibility of modifying a pending order to sell
if(CheckTrailingOrderShort())
return(true);
}
//--- return without operations
return(false);
}
}
//--- check the possibility of opening a position/setting pending order
if(CheckOpen())
return(true);
//--- return without operations
return(false);
}
//+------------------------------------------------------------------+
//| OnTick handler |
//+------------------------------------------------------------------+
void CExpertCustom::OnTick(void)
{
//--- check process flag
if(!m_on_tick_process)
return;
//--- close positions and orders at specified time
if(targetDayOfWeek != -1 && targetMinutes != -1 && targetHour != -1)
{
// Buffer in minutes for checking the condition
int bufferMinutes = 1; // ±1 minute buffer
// Get current server time
datetime currentTimeValue = TimeCurrent();
MqlDateTime currentTime;
TimeToStruct(currentTimeValue, currentTime); // Convert to MqlDateTime
// Extract the current hour and minute
int currentHour = currentTime.hour;
int currentMinute = currentTime.min;
// Check if the current day matches the target day
if(currentTime.day_of_week == targetDayOfWeek || targetDayOfWeek == CLOSE_EVERYDAY)
{
// Check if the current time is within the buffer range around the target time
if(currentHour == targetHour)
{
// Check if the current minute falls within the ±1 minute buffer of the target minute
if(currentMinute >= (targetMinutes - bufferMinutes) && currentMinute <= (targetMinutes + bufferMinutes))
{
// If it matches, call CloseAndDeleteAllForSymbol
if(CloseAndDeleteAllForSymbol())
{
// Log or handle the successful close
Print("Positions and orders closed.");
}
}
}
}
}
CExpertSignalCustom* customSignal = GetCustomSignal();
if(customSignal != NULL)
customSignal.OnTickHandler();
//--- updated quotes and indicators
// Print("Refreshing data...");
if(!Refresh())
return;
// Print("Done.");
//--- expert processing
// Print("Processing...");
Processing();
// Print("Done.");
}
//+------------------------------------------------------------------+
//| OnChartEvent handler |
//+------------------------------------------------------------------+
void CExpertCustom::OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
//--- check process flag
if(!m_on_chart_event_process)
return;
CExpertSignalCustom* customSignal = GetCustomSignal();
if(customSignal != NULL)
customSignal.OnChartEventHandler(id, lparam, dparam, sparam);
}
//+------------------------------------------------------------------+
//| Close all positions and delete all pending orders for Symbol() |
//+------------------------------------------------------------------+
bool CExpertCustom::CloseAndDeleteAllForSymbol()
{
bool result = false; // Track if any action was successfully performed
// Iterate through all positions
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong positionTicket = PositionGetTicket(i);
// Check if the position matches the current symbol and close it
if(PositionSelect(_Symbol) && m_trade.PositionClose(positionTicket))
{
result = true; // A position was successfully closed
}
}
// Iterate through all pending orders
for(int j = OrdersTotal() - 1; j >= 0; j--)
{
ulong orderTicket = OrderGetTicket(j);
// Check if the order matches the current symbol and delete it
if(OrderSelect(orderTicket) && m_trade.OrderDelete(orderTicket))
{
result = true; // An order was successfully deleted
}
}
return result; // Return true if any action was performed, false otherwise
}
//+------------------------------------------------------------------+
//| OnTimer handler |
//+------------------------------------------------------------------+
void CExpertCustom::OnTimer(void)
{
//--- check process flag
if(!m_on_timer_process)
return;
CExpertSignalCustom* customSignal = GetCustomSignal();
if(customSignal != NULL && dbm.OpenDatabase() != false)
{
customSignal.ProcessBufferedSignals();
customSignal.UpdateSignalsWeights();
if(!IsBacktesting)
dbm.CloseDatabase();
}
else
{
// Handle the case where m_signal is not a CExpertSignalCustom
}
}
//+------------------------------------------------------------------+
//| Initialization trade object |
//+------------------------------------------------------------------+
bool CExpertCustom::InitTrade(ulong magic, CExpertTrade *trade = NULL)
{
if(m_trade != NULL)
delete m_trade;
//---
if(trade == NULL)
{
if((m_trade = new CExpertTrade) == NULL)
return(false);
}
else
m_trade = trade;
//--- tune trade object
m_trade.SetSymbol(GetPointer(m_symbol));
m_trade.SetExpertMagicNumber(magic);
m_trade.SetMarginMode();
m_trade.SetAsyncMode(true);
//--- set default deviation for trading in adjusted points
m_trade.SetDeviationInPoints((ulong)(3 * m_adjusted_point / m_symbol.Point()));
//--- ok
return(true);
}
//+------------------------------------------------------------------+