Warrior_EA/Mind/ModalityVolume.mqh

52 lines
2.3 KiB
MQL5

//+------------------------------------------------------------------+
//| ModalityVolume.mqh |
//| AnimateDread |
//| |
//| PARTICIPATION AND EFFORT-VERSUS-RESULT, from tick volume with the |
//| hour-of-day removed (Mind\VolumeProfile.mqh). |
//| |
//| Wyckoff's third law asks whether the result matches the effort. |
//| ABSORB is that comparison in log units: volume well above normal |
//| for the hour on a bar that made little progress (a small range in |
//| ATR) reads high - somebody is taking the other side. Volume that |
//| is normal for the hour with a wide bar reads low - the move had no |
//| one to fight. Tick volume is a proxy for participation on a CFD, |
//| not the real thing; the book records what it turned out to be. |
//+------------------------------------------------------------------+
#ifndef WARRIOR_MODALITYVOLUME_MQH
#define WARRIOR_MODALITYVOLUME_MQH
#include "Modality.mqh"
#include "VolumeProfile.mqh"
class CModalityVolume : public CModality
{
protected:
CBarCache *m_cache; // not owned
CVolumeProfile *m_profile; // not owned
public:
CModalityVolume(CBarCache *cache, CVolumeProfile *profile)
: m_cache(cache), m_profile(profile) {}
virtual string Name(void) const override { return "volume"; }
virtual bool Read(const SBarRef &bar, SMarketContext &ctx) override;
};
//+------------------------------------------------------------------+
bool CModalityVolume::Read(const SBarRef &bar, SMarketContext &ctx)
{
if(m_cache == NULL || m_profile == NULL)
return false;
m_profile.Update();
const double raw = m_profile.Raw(bar.idx);
const double det = m_profile.Detrended(bar.idx);
if(raw == VOLPROF_NA)
return false;
ctx.v[CTX_RVOL_RAW] = raw;
if(det != VOLPROF_NA)
ctx.v[CTX_RVOL] = det;
const double range = ctx.Has(CTX_RANGE_ATR) ? ctx.v[CTX_RANGE_ATR] : CTX_NA;
if(det != VOLPROF_NA && range != CTX_NA)
ctx.v[CTX_ABSORB] = det - MathLog(MathMax(range, 0.1));
return true;
}
#endif // WARRIOR_MODALITYVOLUME_MQH