forked from mnbvc188199/Warrior_EA
- Replaced standard library signal modules with custom implementations to allow for named patterns and improved voting. - Added new input parameters for module weights, allowing for optimization of individual signal contributions. - Enhanced the management of trades with new options for breakeven and management cut. - Introduced a mechanism for dynamic ranking of signal weights based on historical performance. - Improved initialization logic to ensure proper registration of filters and handling of trading conditions. - Added detailed logging for trading permissions and account status during initialization.
175 lines
8.2 KiB
MQL5
175 lines
8.2 KiB
MQL5
//+------------------------------------------------------------------+
| |
//| SignalRegime.mqh |
| |
//| AnimateDread |
| |
//| |
| |
//| WHICH GAME IS BEING PLAYED: trending, consolidating, or mean- |
| |
//| reverting. A classic module in the ordinary shape - it votes |
| |
//| 0..100, names its pattern, and the journal ranks it like any |
| |
//| other. |
| |
//| |
| |
//| WHY THIS AND NOT MORE WYCKOFF. Wyckoff answers "where are we in |
| |
//| a campaign" - events, phases, springs. That is structure. This |
| |
//| answers a blunter and more useful question first: does price |
| |
//| here travel, or does it come back? Those demand opposite trades |
| |
//| from the same indicator reading, which is why an ensemble of |
| |
//| oscillators and trend modules voting together can be right about |
| |
//| everything and still lose: in a trend the oscillators are wrong, |
| |
//| in a range the trend modules are. |
| |
//| |
| |
//| TWO MEASURES, BOTH FROM CLOSES, BOTH SCALE-FREE. |
| |
//| |
| |
//| EFFICIENCY RATIO (Kaufman): net distance divided by the path |
| |
//| length walked to get there. |
| |
//| ER = |C[t] - C[t-n]| / SUM |C[i] - C[i-1]| |
| |
//| 1.0 is a straight line, 0.0 is thrashing that ends where it |
| |
//| began. It needs no volatility estimate and no threshold that |
| |
//| means different things on different symbols - a ratio of two |
| |
//| distances in the same units cancels the instrument entirely. |
| |
//| |
| |
//| VARIANCE RATIO: the variance of q-bar returns against q times the |
| |
//| variance of 1-bar returns. |
| |
//| VR = Var(q-bar) / (q * Var(1-bar)) |
| |
//| A random walk gives 1.0 because variance scales with time. Above |
| |
//| 1 the moves compound - trending. Below 1 they cancel - mean |
| |
//| reverting. This is the sharper of the two: ER says "is there a |
| |
//| trend", VR says "does this market CONTINUE or REVERSE", which is |
| |
//| the question an entry actually rests on. |
| |
//| |
| |
//| ⚠ IT DOES NOT VOTE IN CONSOLIDATION, deliberately. Neither the |
| |
//| trend patterns nor the reversion patterns have an edge when the |
| |
//| market is doing neither, and a module that always finds something |
| |
//| to say is a module whose vote means nothing. Returning 0/0 is a |
| |
//| real answer here, and the standard library counts it as one. |
| |
//+------------------------------------------------------------------+
| |
#ifndef WARRIOR_SIGNALREGIME_MQH
| |
#define WARRIOR_SIGNALREGIME_MQH
| |
| |
#include "..\Expert\WarriorSignal.mqh"
| |
| |
class CSignalRegime : public CWarriorSignal
| |
{
| |
protected:
| |
int m_erPeriod; // bars for the efficiency ratio
| |
int m_vrPeriod; // bars for the variance ratio
| |
int m_vrQ; // the q in VR(q)
| |
int m_maPeriod; // the reference the trend is measured against
| |
double m_erTrend; // ER at or above this is a trend
| |
double m_erChop; // ER at or below this is consolidation
| |
double m_vrRevert; // VR at or below this is mean reverting
| |
| |
int m_pattern_0; // trend, long
| |
int m_pattern_1; // trend, short
| |
int m_pattern_2; // mean reversion, long
| |
int m_pattern_3; // mean reversion, short
| |
| |
double Sma(const int shift, const int period) const;
| |
| |
public:
| |
CSignalRegime(void);
| |
~CSignalRegime(void) {}
| |
| |
void ErPeriod(const int v) { m_erPeriod = v; }
| |
void VrPeriod(const int v) { m_vrPeriod = v; }
| |
void MaPeriod(const int v) { m_maPeriod = v; }
| |
void Pattern_0(const int v) { m_pattern_0 = v; }
| |
void Pattern_1(const int v) { m_pattern_1 = v; }
| |
void Pattern_2(const int v) { m_pattern_2 = v; }
| |
void Pattern_3(const int v) { m_pattern_3 = v; }
| |
virtual void ApplyPatternWeight(int pattern, int weight)
| |
{
| |
if(pattern == 0) m_pattern_0 = weight;
| |
if(pattern == 1) m_pattern_1 = weight;
| |
if(pattern == 2) m_pattern_2 = weight;
| |
if(pattern == 3) m_pattern_3 = weight;
| |
}
| |
//--- Published so the neural module can read the regime as context rather than recompute it.
| |
double ER(const int shift = 1) const { return EfficiencyRatio(shift, m_erPeriod); }
| |
double VR(const int shift = 1) const { return VarianceRatio(shift, m_vrPeriod, m_vrQ); }
| |
| |
virtual bool ValidationSettings(void) override;
| |
virtual int LongCondition(void) override;
| |
virtual int ShortCondition(void) override;
| |
};
| |
//+------------------------------------------------------------------+
| |
CSignalRegime::CSignalRegime(void) : m_erPeriod(20), m_vrPeriod(60), m_vrQ(5), m_maPeriod(50),
| |
m_erTrend(0.35), m_erChop(0.15), m_vrRevert(0.85),
| |
m_pattern_0(60), m_pattern_1(60),
| |
m_pattern_2(50), m_pattern_3(50)
| |
{
| |
m_id = "REGIME";
| |
m_pattern_count = 4;
| |
m_used_series = USE_SERIES_CLOSE;
| |
}
| |
//+------------------------------------------------------------------+
| |
bool CSignalRegime::ValidationSettings(void)
| |
{
| |
if(!CWarriorSignal::ValidationSettings())
| |
return false;
| |
if(m_erPeriod < 5 || m_vrPeriod < 20 || m_vrQ < 2 || m_vrPeriod < m_vrQ * 4)
| |
{
| |
//--- VR(q) needs several non-overlapping q-blocks to estimate a variance at all; with fewer
| |
//--- than four the ratio is noise with a decimal point.
| |
Print("CSignalRegime: periods are too short for a stable variance ratio");
| |
return false;
| |
}
| |
return true;
| |
}
| |
//+------------------------------------------------------------------+
| |
double CSignalRegime::Sma(const int shift, const int period) const
| |
{
| |
double s = 0.0;
| |
for(int i = 0; i < period; i++)
| |
s += Close(shift + i);
| |
return s / period;
| |
}
| |
//+------------------------------------------------------------------+
| |
int CSignalRegime::LongCondition(void)
| |
{
| |
const int idx = StartIndex();
| |
const double er = EfficiencyRatio(idx, m_erPeriod);
| |
const double vr = VarianceRatio(idx, m_vrPeriod, m_vrQ);
| |
const double c = Close(idx);
| |
const double ma = Sma(idx, m_maPeriod);
| |
| |
//--- TRENDING AND UP. ER says the path is efficient, the reference says which way.
| |
if(er >= m_erTrend && c > ma)
| |
{
| |
m_active_pattern = "Pattern_0";
| |
m_active_direction = "Buy";
| |
return m_pattern_0;
| |
}
| |
//--- MEAN REVERTING AND BELOW THE REFERENCE. VR below 1 says moves cancel; being under the mean
| |
//--- is then a reason to buy rather than a reason to worry. This is the exact setup where the
| |
//--- trend modules are wrong, which is the whole point of separating the two regimes.
| |
if(vr <= m_vrRevert && er <= m_erChop && c < ma)
| |
{
| |
m_active_pattern = "Pattern_2";
| |
m_active_direction = "Buy";
| |
return m_pattern_2;
| |
}
| |
return 0;
| |
}
| |
//+------------------------------------------------------------------+
| |
int CSignalRegime::ShortCondition(void)
| |
{
| |
const int idx = StartIndex();
| |
const double er = EfficiencyRatio(idx, m_erPeriod);
| |
const double vr = VarianceRatio(idx, m_vrPeriod, m_vrQ);
| |
const double c = Close(idx);
| |
const double ma = Sma(idx, m_maPeriod);
| |
| |
if(er >= m_erTrend && c < ma)
| |
{
| |
m_active_pattern = "Pattern_1";
| |
m_active_direction = "Sell";
| |
return m_pattern_1;
| |
}
| |
if(vr <= m_vrRevert && er <= m_erChop && c > ma)
| |
{
| |
m_active_pattern = "Pattern_3";
| |
m_active_direction = "Sell";
| |
return m_pattern_3;
| |
}
| |
return 0;
| |
}
| |
#endif // WARRIOR_SIGNALREGIME_MQH
|