forked from animatedread/Warrior_EA
99 lines
3.9 KiB
MQL5
99 lines
3.9 KiB
MQL5
//+------------------------------------------------------------------+
| |||
//| ModalityBreadth.mqh |
| |||
//| AnimateDread |
| |||
//| |
| |||
//| WHAT THE NEIGHBOURING MARKETS ARE DOING at the same bar. |
| |||
//| |
| |||
//| The dip-buy's losses are bear onsets, and bear onsets show up in |
| |||
//| every index at once. A dip that only this index is having is a |
| |||
//| local shake-out; a dip all four are having is a market-wide sell- |
| |||
//| off, which is a different thing to buy. BREADTH is the fraction of |
| |||
//| the peers (this symbol excluded) at z(20) <= -1 on the same bar. |
| |||
//| |
| |||
//| Peers are a comma list; ones the broker does not have are skipped. |
| |||
//| A peer without history for this bar simply does not answer, and |
| |||
//| BREADTH_N says how many did - so a reading from one peer is not |
| |||
//| mistaken for one from three. |
| |||
//+------------------------------------------------------------------+
| |||
#ifndef WARRIOR_MODALITYBREADTH_MQH
| |||
#define WARRIOR_MODALITYBREADTH_MQH
| |||
| |||
#include "Modality.mqh"
| |||
| |||
class CModalityBreadth : public CModality
| |||
{
| |||
protected:
| |||
string m_self;
| |||
ENUM_TIMEFRAMES m_tf;
| |||
string m_peers[];
| |||
int m_period; // z-score window
| |||
double m_dipZ; // a peer at or below this z counts as dipping
| |||
| |||
bool PeerZ(const string peer, const datetime when, double &z) const;
| |||
| |||
public:
| |||
CModalityBreadth(const string self, const ENUM_TIMEFRAMES tf,
| |||
const string peerList, const int period = 20,
| |||
const double dipZ = -1.0)
| |||
: m_self(self), m_tf(tf), m_period(period), m_dipZ(dipZ)
| |||
{
| |||
string all[];
| |||
const int n = StringSplit(peerList, ',', all);
| |||
for(int i = 0; i < n; i++)
| |||
{
| |||
StringTrimLeft(all[i]);
| |||
StringTrimRight(all[i]);
| |||
if(all[i] == "" || all[i] == m_self)
| |||
continue;
| |||
if(!SymbolSelect(all[i], true))
| |||
continue;
| |||
const int k = ArraySize(m_peers);
| |||
ArrayResize(m_peers, k + 1);
| |||
m_peers[k] = all[i];
| |||
}
| |||
}
| |||
int PeerCount(void) const { return ArraySize(m_peers); }
| |||
virtual string Name(void) const override { return "breadth"; }
| |||
virtual bool Read(const SBarRef &bar, SMarketContext &ctx) override;
| |||
};
| |||
//+------------------------------------------------------------------+
| |||
bool CModalityBreadth::PeerZ(const string peer, const datetime when, double &z) const
| |||
{
| |||
const int shift = iBarShift(peer, m_tf, when, false);
| |||
if(shift < 0)
| |||
return false;
| |||
double c[];
| |||
if(CopyClose(peer, m_tf, shift, m_period, c) != m_period)
| |||
return false;
| |||
double s = 0.0, s2 = 0.0;
| |||
for(int i = 0; i < m_period; i++)
| |||
{
| |||
s += c[i];
| |||
s2 += c[i] * c[i];
| |||
}
| |||
const double mean = s / m_period, var = s2 / m_period - mean * mean;
| |||
if(var <= 0.0)
| |||
return false;
| |||
z = (c[m_period - 1] - mean) / MathSqrt(var); // oldest first: the last element is `shift`
| |||
return true;
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
bool CModalityBreadth::Read(const SBarRef &bar, SMarketContext &ctx)
| |||
{
| |||
int answered = 0, dipping = 0;
| |||
for(int i = 0; i < ArraySize(m_peers); i++)
| |||
{
| |||
double z;
| |||
if(!PeerZ(m_peers[i], bar.time, z))
| |||
continue;
| |||
answered++;
| |||
if(z <= m_dipZ)
| |||
dipping++;
| |||
}
| |||
ctx.v[CTX_BREADTH_N] = answered;
| |||
if(answered == 0)
| |||
return false;
| |||
ctx.v[CTX_BREADTH] = (double)dipping / answered;
| |||
return true;
| |||
}
| |||
#endif // WARRIOR_MODALITYBREADTH_MQH
|