forked from animatedread/Warrior_EA
- Introduced `FeatureScale.mqh` with `FeatSquash` function for stateless feature scaling. - Added `RegimeMath.mqh` class for regime arithmetic, including efficiency and variance calculations. - Documented the Mind trading logic in `MIND.md`, detailing the trading process and modes. - Created `VOLNORM_PLAN.md` and `VOLNORM_RESULTS.md` for tick-volume normalization testing. - Implemented `read_book.py` for analyzing trade book data and correlations. - Developed `volnorm.py` for testing tick-volume normalization with new and old methods.
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
|