forked from mnbvc188199/Warrior_EA
200 lines
9.4 KiB
MQL5
200 lines
9.4 KiB
MQL5
//+------------------------------------------------------------------+
| |
//| SignalWyckoffEvent.mqh |
| |
//| AnimateDread |
| |
//| |
| |
//| The ADWyckoffEventStream as a CLASSIC VOTE MODULE. |
| |
//| |
| |
//| It states an opinion; it does not own a trade. That distinction |
| |
//| is the one IsClassicVoter() now tests (OwnsTrade() == false), and |
| |
//| it is deliberate here: the event stream says "this is a spring in |
| |
//| phase C of an accumulation", which is a reason to lean long, not |
| |
//| a complete strategy with an entry, a stop and a target. The book |
| |
//| setups own trades; this module votes alongside the fifteen other |
| |
//| classic modules and is weighted like them. |
| |
//| |
| |
//| PATTERNS, ordered by the book's own conviction (Wyckoff's phases |
| |
//| are a sequence, and later phases are later BECAUSE they are more |
| |
//| confirmed): |
| |
//| 0 Spring / UTAD, graded 1-3 by the indicator. The shake. The |
| |
//| highest-conviction entry the method has, and the grade is |
| |
//| the indicator's own confidence in it. |
| |
//| 1 SOS / SOW - phase D confirmation, the range resolving. |
| |
//| 2 LPS / LPSY - the pullback that holds after an SOS. |
| |
//| 3 Test, placed well (upper half of an accumulation / below a |
| |
//| climax), with the range character agreeing. |
| |
//| 4 Change of character, range -> trend, with slope context. |
| |
//| |
| |
//| ALL READS GO THROUGH CWyckoffFeed AT SHIFT 1. Nothing here knows |
| |
//| a buffer index; when the indicator is revised again this file |
| |
//| does not change unless the MEANING changed. |
| |
//+------------------------------------------------------------------+
| |
#ifndef WARRIOR_SIGNALWYCKOFFEVENT_MQH
| |
#define WARRIOR_SIGNALWYCKOFFEVENT_MQH
| |
| |
#include "..\..\Expert\WarriorSignal.mqh"
| |
#include "WyckoffFeed.mqh"
| |
| |
class CSignalWyckoffEvent : public CWarriorSignal
| |
{
| |
protected:
| |
//--- indicator inputs, exposed so a sweep can move them without editing this file
| |
int m_lookback;
| |
int m_zigzag;
| |
int m_arLegs;
| |
double m_boundaryTol;
| |
int m_maxRangeBars;
| |
//--- pattern weights (0-100)
| |
int m_pattern_0; // spring / UTAD, scaled by the indicator's grade
| |
int m_pattern_1; // SOS / SOW
| |
int m_pattern_2; // LPS / LPSY
| |
int m_pattern_3; // well-placed test
| |
int m_pattern_4; // change of character, range -> trend
| |
| |
public:
| |
CSignalWyckoffEvent(void);
| |
~CSignalWyckoffEvent(void) {}
| |
void Lookback(const int v) { m_lookback = v; }
| |
void ZigZag(const int v) { m_zigzag = v; }
| |
void ARLegs(const int v) { m_arLegs = v; }
| |
void BoundaryTol(const double v) { m_boundaryTol = v; }
| |
void MaxRangeBars(const int v) { m_maxRangeBars = 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; }
| |
void Pattern_4(const int v) { m_pattern_4 = v; }
| |
virtual void ApplyPatternWeight(int patternNumber, int weight);
| |
virtual bool InitIndicators(CIndicators *indicators);
| |
virtual int LongCondition(void);
| |
virtual int ShortCondition(void);
| |
//--- The feed is the shared g_wyckoffFeed - see WyckoffFeedEnsure(). Nothing owns it.
| |
| |
protected:
| |
//--- One implementation, mirrored by direction. `dir` is +1 for the long case, -1 for the short,
| |
//--- and every comparison below is written against it so the two sides cannot drift apart -
| |
//--- which is exactly how m_entry came to be wiped by its own other side (project note 09-08).
| |
int Condition(const int dir);
| |
void Note(const int pattern, const int dir);
| |
};
| |
//+------------------------------------------------------------------+
| |
CSignalWyckoffEvent::CSignalWyckoffEvent(void) :
| |
m_lookback(50), m_zigzag(3), m_arLegs(3), m_boundaryTol(0.50), m_maxRangeBars(200),
| |
m_pattern_0(80), m_pattern_1(60), m_pattern_2(45), m_pattern_3(30), m_pattern_4(20)
| |
{
| |
m_id = "WYKEV";
| |
m_pattern_count = 5;
| |
m_used_series = USE_SERIES_OPEN + USE_SERIES_HIGH + USE_SERIES_LOW + USE_SERIES_CLOSE;
| |
}
| |
//+------------------------------------------------------------------+
| |
void CSignalWyckoffEvent::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;
| |
case 3: Pattern_3(weight); break;
| |
case 4: Pattern_4(weight); break;
| |
default: break;
| |
}
| |
}
| |
//+------------------------------------------------------------------+
| |
bool CSignalWyckoffEvent::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, m_arLegs, m_boundaryTol, m_maxRangeBars))
| |
{
| |
//--- LOUD, AND FATAL. A feed that did not load reads zeros, and zeros are indistinguishable
| |
//--- from "no Wyckoff event here" - the module would abstain forever and look healthy.
| |
PrintFormat("%s: WYCKOFF FEED FAILED - %s. This module cannot vote and init is refused rather"
| |
" than leaving a silent abstainer in the divisor.", __FUNCTION__, g_wyckoffFeed.Why());
| |
return(false);
| |
}
| |
return(true);
| |
}
| |
//+------------------------------------------------------------------+
| |
int CSignalWyckoffEvent::LongCondition(void)
| |
{
| |
return Condition(+1);
| |
}
| |
//+------------------------------------------------------------------+
| |
int CSignalWyckoffEvent::ShortCondition(void)
| |
{
| |
return Condition(-1);
| |
}
| |
//+------------------------------------------------------------------+
| |
//--- Names the pattern that produced this vote. The journal keys its tables on it, so it is part of
| |
//--- the module's contract with the database rather than a log string: change one of these names and
| |
//--- that pattern's history splits into a before and an after that nothing will ever join up.
| |
void CSignalWyckoffEvent::Note(const int pattern, const int dir)
| |
{
| |
m_active_pattern = "Pattern_" + IntegerToString(pattern);
| |
m_active_direction = (dir > 0) ? "Buy" : "Sell";
| |
}
| |
//+------------------------------------------------------------------+
| |
int CSignalWyckoffEvent::Condition(const int dir)
| |
{
| |
if(!g_wyckoffFeed.Ok())
| |
return 0;
| |
| |
const int code = g_wyckoffFeed.EventCode(); // 0..9, direction stripped
| |
const int evDir = g_wyckoffFeed.EventDir(); // +1 bullish structure, -1 bearish, 0 none
| |
const double grade = g_wyckoffFeed.SpringGrade(); // +-1..+-3 on the shake bar
| |
const double charact = g_wyckoffFeed.Character(); // +1 accumulation, -1 distribution
| |
const int phase = g_wyckoffFeed.PhaseLetter(); // 1..5 = A..E
| |
| |
//--- 0: THE SHAKE. Graded by the indicator, and the grade is carried through to the vote rather
| |
//--- than flattened: grade 3 is "direct entry", grade 1 is "wait for the test", and a module that
| |
//--- returned the same weight for both would be discarding the indicator's own confidence.
| |
if(code == WYK_EV_SPRING && evDir == dir)
| |
{
| |
Note(0, dir);
| |
const int g = (int)MathAbs(grade);
| |
if(g >= 1 && g <= 3)
| |
return (int)MathRound(m_pattern_0 * (g / 3.0));
| |
return m_pattern_0 / 2; // a spring the grader could not rank
| |
}
| |
| |
//--- 1: PHASE D CONFIRMATION. The range is resolving in `dir`.
| |
if(code == WYK_EV_SOS && evDir == dir)
| |
{
| |
Note(1, dir);
| |
return m_pattern_1;
| |
}
| |
| |
//--- 2: THE PULLBACK THAT HELD.
| |
if(code == WYK_EV_LPS && evDir == dir)
| |
{
| |
Note(2, dir);
| |
return m_pattern_2;
| |
}
| |
| |
//--- 3: A WELL-PLACED TEST. The test alone is weak; the test plus a range whose character agrees
| |
//--- with the side being voted is the book's actual condition, so both are required.
| |
if(code == WYK_EV_TEST && evDir == dir)
| |
{
| |
const double place = g_wyckoffFeed.TestPlace();
| |
const bool characterAgrees = (dir > 0) ? (charact > 0.0) : (charact < 0.0);
| |
const bool placedWell = (dir > 0) ? (place > 0.0) : (place < 0.0);
| |
if(characterAgrees && placedWell)
| |
{
| |
Note(3, dir);
| |
return m_pattern_3;
| |
}
| |
}
| |
| |
//--- 4: CHANGE OF CHARACTER, range -> trend, only while the phase agrees with the side. Phase is
| |
//--- signed by direction in the buffer, so PhaseDir() is what makes this directional at all.
| |
if(g_wyckoffFeed.ChochRangeToTrend() != 0.0 && g_wyckoffFeed.PhaseDir() == dir && phase >= WYK_PHASE_D)
| |
{
| |
Note(4, dir);
| |
return m_pattern_4;
| |
}
| |
| |
return 0;
| |
}
| |
#endif // WARRIOR_SIGNALWYCKOFFEVENT_MQH
|