mql5/Include/Experts/Core/EAState.mqh
2025-08-16 12:30:04 -04:00

277 lines
8.4 KiB
MQL5

//+------------------------------------------------------------------+
//| EAState.mqh |
//| Copyright 2025, Your Company Name |
//| https://www.yoursite.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, Your Company Name"
#property link "https://www.yoursite.com"
#property version "1.00"
#property strict
#include "EALogger.mqh"
//+------------------------------------------------------------------+
//| Market data state |
//+------------------------------------------------------------------+
struct SMarketData
{
MqlTick lastTick; // Last tick data
datetime lastUpdate; // Last update time
double bid, ask; // Current prices
double spread; // Current spread
// Initialize structure
void Init()
{
ZeroMemory(lastTick);
lastUpdate = 0;
bid = ask = spread = 0.0;
}
};
//+------------------------------------------------------------------+
//| Trade state |
//+------------------------------------------------------------------+
struct STradeState
{
int totalPositions; // Total open positions
double totalProfit; // Total profit/loss
double maxDrawdown; // Maximum drawdown
datetime lastTradeTime; // Time of last trade
// Initialize structure
void Init()
{
totalPositions = 0;
totalProfit = 0.0;
maxDrawdown = 0.0;
lastTradeTime = 0;
}
};
//+------------------------------------------------------------------+
//| EA State Manager |
//+------------------------------------------------------------------+
class CEAState
{
private:
CEALogger* m_logger; // Logger instance
SMarketData m_marketData; // Market data state
STradeState m_tradeState; // Trade state
// Indicators
int m_maHandle; // Moving average handle
double m_maBuffer[]; // MA buffer
// Locks
bool m_isUpdating; // Update flag
// Internal methods
void UpdateIndicators();
public:
CEAState() : m_logger(NULL), m_maHandle(INVALID_HANDLE), m_isUpdating(false)
{
m_marketData.Init();
m_tradeState.Init();
}
~CEAState() { Deinitialize(); }
// Initialization
bool Initialize(CEALogger* logger);
void Deinitialize();
// State updates
void UpdateMarketData(const string symbol, ENUM_TIMEFRAMES timeframe);
void UpdateLastTick(const CTickEvent* tick);
void UpdateTradeState();
// Getters
const SMarketData& GetMarketData() const { return m_marketData; }
const STradeState& GetTradeState() const { return m_tradeState; }
// Indicator access
double GetMA(int shift = 0) const;
// State validation
bool IsMarketOpen() const;
bool IsTradingAllowed() const;
};
//+------------------------------------------------------------------+
//| Initialize state manager |
//+------------------------------------------------------------------+
bool CEAState::Initialize(CEALogger* logger)
{
if (logger == NULL)
return false;
m_logger = logger;
// Initialize indicators
m_maHandle = iMA(NULL, 0, 14, 0, MODE_SMA, PRICE_CLOSE);
if (m_maHandle == INVALID_HANDLE)
{
m_logger.LogError("Failed to initialize MA indicator");
return false;
}
// Set indicator buffers
ArraySetAsSeries(m_maBuffer, true);
m_logger.LogInfo("State manager initialized");
return true;
}
//+------------------------------------------------------------------+
//| Deinitialize state manager |
//+------------------------------------------------------------------+
void CEAState::Deinitialize()
{
// Release indicators
if (m_maHandle != INVALID_HANDLE)
{
IndicatorRelease(m_maHandle);
m_maHandle = INVALID_HANDLE;
}
// Clear buffers
ArrayFree(m_maBuffer);
m_logger = NULL;
}
//+------------------------------------------------------------------+
//| Update market data |
//+------------------------------------------------------------------+
void CEAState::UpdateMarketData(const string symbol, ENUM_TIMEFRAMES timeframe)
{
if (m_isUpdating)
return;
m_isUpdating = true;
// Update tick data
MqlTick lastTick;
if (SymbolInfoTick(symbol, lastTick))
{
m_marketData.lastTick = lastTick;
m_marketData.bid = lastTick.bid;
m_marketData.ask = lastTick.ask;
m_marketData.spread = lastTick.ask - lastTick.bid;
m_marketData.lastUpdate = TimeCurrent();
}
// Update indicators
UpdateIndicators();
m_isUpdating = false;
}
//+------------------------------------------------------------------+
//| Update last tick |
//+------------------------------------------------------------------+
void CEAState::UpdateLastTick(const CTickEvent* tick)
{
if (tick == NULL)
return;
// Update tick data from event
// Implementation depends on CTickEvent structure
}
//+------------------------------------------------------------------+
//| Update trade state |
//+------------------------------------------------------------------+
void CEAState::UpdateTradeState()
{
// Update positions count
m_tradeState.totalPositions = PositionsTotal();
// Update total profit
double totalProfit = 0;
for (int i = 0; i < m_tradeState.totalPositions; i++)
{
if (m_position.SelectByIndex(i))
totalProfit += m_position.Profit() + m_position.Swap() + m_position.Commission();
}
m_tradeState.totalProfit = totalProfit;
// Update max drawdown
if (totalProfit < m_tradeState.maxDrawdown)
m_tradeState.maxDrawdown = totalProfit;
// Update last trade time
if (m_tradeState.totalPositions > 0)
m_tradeState.lastTradeTime = TimeCurrent();
}
//+------------------------------------------------------------------+
//| Update indicators |
//+------------------------------------------------------------------+
void CEAState::UpdateIndicators()
{
if (m_maHandle == INVALID_HANDLE)
return;
// Copy MA values
if (CopyBuffer(m_maHandle, 0, 0, 1, m_maBuffer) != 1)
{
if (m_logger != NULL)
m_logger.LogError("Failed to copy MA buffer");
return;
}
}
//+------------------------------------------------------------------+
//| Get moving average value |
//+------------------------------------------------------------------+
double CEAState::GetMA(int shift = 0) const
{
if (shift < 0 || shift >= ArraySize(m_maBuffer))
return 0.0;
return m_maBuffer[shift];
}
//+------------------------------------------------------------------+
//| Check if market is open |
//+------------------------------------------------------------------+
bool CEAState::IsMarketOpen() const
{
// Check if current time is within trading hours
MqlDateTime dt;
TimeToStruct(TimeCurrent(), dt);
// Example: Check if it's a weekday and within trading hours
if (dt.day_of_week == 0 || dt.day_of_week == 6) // Weekend
return false;
// Example: Check trading hours (9:30 AM - 4:00 PM)
int currentMinute = dt.hour * 60 + dt.min;
if (currentMinute < 570 || currentMinute >= 960) // Before 9:30 AM or after 4:00 PM
return false;
return true;
}
//+------------------------------------------------------------------+
//| Check if trading is allowed |
//+------------------------------------------------------------------+
bool CEAState::IsTradingAllowed() const
{
// Check if market is open
if (!IsMarketOpen())
return false;
// Check if max positions reached
if (m_tradeState.totalPositions >= 10) // Example limit
return false;
// Check if max drawdown reached
if (m_tradeState.maxDrawdown <= -1000.0) // Example limit
return false;
return true;
}