#ifndef CORE_COMMON_MQH #define CORE_COMMON_MQH //+------------------------------------------------------------------+ //| common.mqh - conventions and the one data structure core/ shares | //| | //| Contract for every core/*.mqh: | //| - rates[] is AS-SERIES: [0] = forming bar, [1] = last closed | //| bar, higher index = older. Callers do CopyRates() then | //| ArraySetAsSeries(rates, true). | //| - Nothing reads globals or chart state. Data comes in by | //| argument, so any symbol/timeframe can be scanned. | //| - Direction flags are ints: +1 bullish, -1 bearish, 0 none. | //| - Memory is bounded: history lives in CRing, never in a | //| structure that grows per tick. | //| - update() methods are safe to call every tick; they act once | //| per new closed bar. | //+------------------------------------------------------------------+ //--- true when rates[] is as-series and holds at least minBars bars bool CoreSeriesReady(const MqlRates &rates[], const int minBars) { return ArrayGetAsSeries(rates) && ArraySize(rates) >= minBars; } //+------------------------------------------------------------------+ //| CRing - fixed-capacity ring buffer | //| Push O(1), evicts the oldest entry when full | //| At O(1), pos 0 = newest, Count()-1 = oldest | //+------------------------------------------------------------------+ template class CRing { private: T m_buf[]; int m_cap; int m_head; // slot of the NEXT write int m_count; // valid entries, never above m_cap public: CRing() : m_cap(0), m_head(0), m_count(0) {} bool Init(const int capacity) { if(capacity <= 0 || ArrayResize(m_buf, capacity) != capacity) return false; m_cap = capacity; m_head = 0; m_count = 0; return true; } void Clear() { m_head = 0; m_count = 0; } int Count() const { return m_count; } int Capacity() const { return m_cap; } bool Push(const T &value) { if(m_cap == 0) return false; m_buf[m_head] = value; m_head = (m_head + 1) % m_cap; if(m_count < m_cap) m_count++; return true; } bool At(const int pos, T &out) const { if(pos < 0 || pos >= m_count) return false; out = m_buf[(m_head - 1 - pos + m_cap) % m_cap]; return true; } }; #endif // CORE_COMMON_MQH