//+------------------------------------------------------------------+ //| MarketData.mqh - Market data wrapper | //| Handles bid/ask, spread, symbol info, new bar detection | //+------------------------------------------------------------------+ #ifndef __MARKETDATA_MQH__ #define __MARKETDATA_MQH__ #include "Config.mqh" #include "Logger.mqh" #include "Utilities.mqh" class CMarketData { private: string m_symbol; CLogger *mp_logger; datetime m_last_bar_time; int m_digits; double m_point; public: // Constructor CMarketData(const string symbol, CLogger *logger) { m_symbol = symbol; mp_logger = logger; m_last_bar_time = 0; m_digits = CUtilities::GetDigits(symbol); m_point = CUtilities::GetPoint(symbol); } // Get current bid price double GetBid() const { return SymbolInfoDouble(m_symbol, SYMBOL_BID); } // Get current ask price double GetAsk() const { return SymbolInfoDouble(m_symbol, SYMBOL_ASK); } // Get current spread in points int GetSpreadPoints() const { double spread_price = GetAsk() - GetBid(); return CUtilities::PriceToPoints(m_symbol, spread_price); } // Get current spread in price double GetSpreadPrice() const { return GetAsk() - GetBid(); } // Check if spread is acceptable bool IsSpreadAcceptable(int max_spread_points) const { int current_spread = GetSpreadPoints(); if(current_spread > max_spread_points) { if(mp_logger) { // Build message without using variadic StringFormat to avoid parser issues string msg = "Spread too wide: "; msg += IntegerToString(current_spread); msg += " > "; msg += IntegerToString(max_spread_points); mp_logger.Warning(msg); } return false; } return true; } // Detect new bar on current timeframe bool IsNewBar() { datetime bar_time = iTime(m_symbol, PERIOD_CURRENT, 0); if(m_last_bar_time == 0) { m_last_bar_time = bar_time; return true; } if(bar_time != m_last_bar_time) { m_last_bar_time = bar_time; return true; } return false; } // Get current close price double GetClose() const { return iClose(m_symbol, PERIOD_CURRENT, 0); } // Get current open price double GetOpen() const { return iOpen(m_symbol, PERIOD_CURRENT, 0); } // Get current high price double GetHigh() const { return iHigh(m_symbol, PERIOD_CURRENT, 0); } // Get current low price double GetLow() const { return iLow(m_symbol, PERIOD_CURRENT, 0); } // Get close price of bar N bars ago double GetCloseAt(int shift) const { return iClose(m_symbol, PERIOD_CURRENT, shift); } // Get open price of bar N bars ago double GetOpenAt(int shift) const { return iOpen(m_symbol, PERIOD_CURRENT, shift); } // Get symbol digits int GetDigits() const { return m_digits; } // Get symbol point double GetPoint() const { return m_point; } // Check if trading is allowed for this symbol bool IsTradingAllowed() const { // Ensure symbol allows trading (full trade mode) long trade_mode = (long)SymbolInfoInteger(m_symbol, SYMBOL_TRADE_MODE); if(trade_mode != SYMBOL_TRADE_MODE_FULL) return false; // Basic check: ensure symbol is tradeable (has non-zero point and digits) if(SymbolInfoDouble(m_symbol, SYMBOL_POINT) <= 0.0) return false; return true; } // Get symbol name string GetSymbol() const { return m_symbol; } // Get minimum volume double GetMinVolume() const { return SymbolInfoDouble(m_symbol, SYMBOL_VOLUME_MIN); } // Get maximum volume double GetMaxVolume() const { return SymbolInfoDouble(m_symbol, SYMBOL_VOLUME_MAX); } // Get volume step double GetVolumeStep() const { return SymbolInfoDouble(m_symbol, SYMBOL_VOLUME_STEP); } }; #endif //__MARKETDATA_MQH__