Warrior_EA/Mind/ModalityBreadth.mqh
AnimateDread e9c562b39f Add Feature Scaling and Regime Math Classes; Implement Mind Trading Logic
- 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.
2026-09-30 18:36:33 -04:00

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