//+------------------------------------------------------------------+ //| SignalWyckoffStructure.mqh | //| AnimateDread | //| | //| ADWyckoffFailedStructure + ADWyckoffSignificantBarInversion as | //| one classic vote module. | //| | //| Both indicators publish a SIGNED QUALITY on buffer 0, and this | //| module reads that rather than re-deriving a direction from the | //| flag buffers. That is a deliberate choice, because the flag names | //| are a trap: | //| | //| BullishStructuralFailure -> signedValue += quality -> BULLISH | //| "higher low, no weakness" - it is the DOWN leg that failed. | //| Read as "a bullish structure failed" it inverts the signal. | //| FailedDistribution -> signedValue += quality -> BULLISH | //| "breakdown failed" | //| FailedAccumulation -> signedValue -= quality -> BEARISH | //| "breakout failed" | //| | //| (ADWyckoffFailedStructure.mq5:332-338.) The indicator also makes | //| its two structural flags mutually exclusive precisely so the | //| signed value cannot net to zero - a defect it fixed in v2.0. Using | //| buffer 0 inherits that arbitration instead of re-implementing it | //| here and getting a different answer. | //| | //| The magnitudes are the indicators' own confidence and are carried | //| through: FailedStructure clamps to +-2.5, SignificantBarInversion | //| to +-2.0. Both are scaled to the pattern weight rather than | //| flattened to a flag. | //+------------------------------------------------------------------+ #ifndef WARRIOR_SIGNALWYCKOFFSTRUCTURE_MQH #define WARRIOR_SIGNALWYCKOFFSTRUCTURE_MQH #include "..\..\Expert\WarriorSignal.mqh" #include "WyckoffFeed.mqh" //--- The clamps the two indicators apply to their signed quality. Named because they are the //--- denominators that turn a quality into a fraction of a pattern weight; a wrong one here silently //--- rescales the vote rather than breaking it. #define WYK_FAIL_QUALITY_MAX 2.5 #define WYK_SBI_QUALITY_MAX 2.0 class CSignalWyckoffStructure : public CWarriorSignal { protected: int m_lookback; int m_zigzag; //--- pattern weights (0-100) int m_pattern_0; // structural failure / failed breakout, scaled by its quality int m_pattern_1; // significant bar with a control flip - the strongest SBI case int m_pattern_2; // significant bar alone, scaled by its quality public: CSignalWyckoffStructure(void); ~CSignalWyckoffStructure(void) {} void Lookback(const int v) { m_lookback = v; } void ZigZag(const int v) { m_zigzag = 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; } virtual void ApplyPatternWeight(int patternNumber, int weight); virtual bool InitIndicators(CIndicators *indicators); virtual int LongCondition(void) { return Condition(+1); } virtual int ShortCondition(void) { return Condition(-1); } protected: int Condition(const int dir); //--- Names the pattern for the journal; see the note in SignalWyckoffEvent.mqh. void Note(const int pattern, const int dir) { m_active_pattern = "Pattern_" + IntegerToString(pattern); m_active_direction = (dir > 0) ? "Buy" : "Sell"; } //--- quality -> 0..weight, saturating at the indicator's own clamp int Scaled(const double quality, const double clamp, const int weight) { const double f = MathMin(MathAbs(quality) / clamp, 1.0); return (int)MathRound(weight * f); } }; //+------------------------------------------------------------------+ CSignalWyckoffStructure::CSignalWyckoffStructure(void) : m_lookback(50), m_zigzag(3), m_pattern_0(55), m_pattern_1(40), m_pattern_2(25) { m_id = "WYKST"; m_pattern_count = 3; m_used_series = USE_SERIES_OPEN + USE_SERIES_HIGH + USE_SERIES_LOW + USE_SERIES_CLOSE + USE_SERIES_TICK_VOLUME; } //+------------------------------------------------------------------+ void CSignalWyckoffStructure::ApplyPatternWeight(int patternNumber, int weight) { switch(patternNumber) { case 0: Pattern_0(weight); break; case 1: Pattern_1(weight); break; case 2: Pattern_2(weight); break; default: break; } } //+------------------------------------------------------------------+ bool CSignalWyckoffStructure::InitIndicators(CIndicators *indicators) { if(indicators == NULL) return(false); if(!CWarriorSignal::InitIndicators(indicators)) return(false); if(!WyckoffFeedEnsure(indicators, m_symbol.Name(), m_period, m_lookback, m_zigzag)) { PrintFormat("%s: WYCKOFF FEED FAILED - %s. Refusing init rather than voting zeros, which are" " indistinguishable from 'no structure here'.", __FUNCTION__, g_wyckoffFeed.Why()); return(false); } return(true); } //+------------------------------------------------------------------+ int CSignalWyckoffStructure::Condition(const int dir) { if(!g_wyckoffFeed.Ok()) return 0; //--- 0: FAILED STRUCTURE. One signed number covering all four of the indicator's cases, already //--- arbitrated by it. Sign is the direction the failure hands control to. const double fail = g_wyckoffFeed.FailValue(); if(fail != 0.0 && ((dir > 0) ? (fail > 0.0) : (fail < 0.0))) { Note(0, dir); return Scaled(fail, WYK_FAIL_QUALITY_MAX, m_pattern_0); } //--- 1 and 2: THE SIGNIFICANT BAR. A control FLIP is the book's stronger statement - the bar did //--- not merely show intent, it took control - so it is tested first and weighted above the bar //--- on its own. Quality is signed the same way (+ bull / - bear). const double q = g_wyckoffFeed.BarQuality(); if(q != 0.0 && ((dir > 0) ? (q > 0.0) : (q < 0.0))) { const bool flip = (dir > 0) ? (g_wyckoffFeed.BullFlip() != 0.0) : (g_wyckoffFeed.BearFlip() != 0.0); if(flip) { Note(1, dir); return Scaled(q, WYK_SBI_QUALITY_MAX, m_pattern_1); } const bool sig = (dir > 0) ? (g_wyckoffFeed.BullBar() != 0.0) : (g_wyckoffFeed.BearBar() != 0.0); if(sig) { Note(2, dir); return Scaled(q, WYK_SBI_QUALITY_MAX, m_pattern_2); } } return 0; } #endif // WARRIOR_SIGNALWYCKOFFSTRUCTURE_MQH