//+------------------------------------------------------------------+ //| 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; }