//+------------------------------------------------------------------+ //| VolumeFeed.mqh | //| AnimateDread | //| | //| ONE PLACE THAT ANSWERS "HOW BUSY WAS THIS BAR, FOR ITS HOUR". | //| | //| The neural module and the management net each used to compute | //| their own bar-over-recent-mean volume ratio, and both carried the | //| same defect (see Mind\VolumeProfile.mqh: the ratio mostly encoded | //| the hour of day). They now ask this feed instead, so there is one | //| definition of relative volume in the codebase and one place to fix | //| it. The Mind's own volume modality reads the same profile. | //| | //| One feed per chart, guarded by the symbol/period it was built for, | //| like g_wyckoffFeed. It owns a bar cache of the whole history - the | //| stdlib series stop at shift 1023 and the neural module trains far | //| deeper than that. | //+------------------------------------------------------------------+ #ifndef WARRIOR_VOLUMEFEED_MQH #define WARRIOR_VOLUMEFEED_MQH #include "VolumeProfile.mqh" class CVolumeFeed { protected: CBarCache m_cache; CVolumeProfile m_profile; string m_for; public: CVolumeFeed(void) : m_for("") {} bool Ensure(const string symbol, const ENUM_TIMEFRAMES tf) { const string want = symbol + "/" + IntegerToString((int)tf); if(m_for == want) return true; m_cache.Init(symbol, tf, 14, 30); m_profile.Init(GetPointer(m_cache)); m_for = want; return true; } //--- Bring the cache up to the newest closed bar and fold it into the profile. bool Sync(void) { if(m_for == "" || !m_cache.Sync()) return false; m_profile.Update(); return true; } //--- The bar that OPENED at `barTime`: its level-detrended log volume against the hour's norm, //--- that reading's mean over the last five bars, and its change from the previous bar. //--- False when any of them is not yet defined - the caller drops the row, as it does for any //--- other feature it cannot compute. bool Reading(const datetime barTime, double &now, double &mean5, double &change) const { const int i = m_cache.IndexOf(barTime); if(i < 5) return false; now = m_profile.Detrended(i); const double prev = m_profile.Detrended(i - 1); if(now == VOLPROF_NA || prev == VOLPROF_NA) return false; double s = now; for(int k = 1; k < 5; k++) { const double d = m_profile.Detrended(i - k); if(d == VOLPROF_NA) return false; s += d; } mean5 = s / 5.0; change = now - prev; return true; } }; CVolumeFeed g_volFeed; #endif // WARRIOR_VOLUMEFEED_MQH