2026-07-26 18:33:12 -04:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| SignalIchimoku.mqh |
|
|
|
|
|
//| AnimateDread |
|
|
|
|
|
//| https://www.mql5.com |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
#include "..\Expert\ExpertSignalCustom.mqh"
|
|
|
|
|
// wizard description start
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| Description of the class |
|
|
|
|
|
//| Title=Signals of indicator 'Ichimoku Kinko Hyo' |
|
|
|
|
|
//| Type=SignalAdvanced |
|
|
|
|
|
//| Name=Ichimoku |
|
|
|
|
|
//| ShortName=Ichimoku |
|
|
|
|
|
//| Class=CSignalIchimoku |
|
|
|
|
|
//| Page=signal_ichimoku |
|
|
|
|
|
//| Parameter=PeriodTenkan,int,9,Tenkan-sen period |
|
|
|
|
|
//| Parameter=PeriodKijun,int,26,Kijun-sen period |
|
|
|
|
|
//| Parameter=PeriodSenkou,int,52,Senkou Span B period |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
// wizard description end
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| Class CSignalIchimoku. |
|
|
|
|
|
//| Purpose: Class of generator of trade signals based on the |
|
|
|
|
|
//| 'Ichimoku Kinko Hyo' indicator. |
|
|
|
|
|
//| Is derived from the CExpertSignalCustom class. |
|
|
|
|
|
//| |
|
|
|
|
|
//| Written from scratch - unlike MA/RSI/MACD there is NO Ichimoku |
|
|
|
|
|
//| signal module in the MQL5 standard library to port, so the |
|
|
|
|
|
//| twelve market models below encode the conventional Ichimoku |
|
|
|
|
|
//| readings directly rather than inheriting a stock pattern set. |
|
|
|
|
|
//| Between them they cover the full canonical repertoire: |
|
|
|
|
|
//| |
|
|
|
|
|
//| - Tenkan/Kijun cross, GRADED the classic three ways by where |
|
|
|
|
|
//| the cross happens relative to the Kumo: below it = weak |
|
|
|
|
|
//| (model 3), inside it = neutral (model 5), above it = strong |
|
|
|
|
|
//| (model 10), mirrored for shorts. Grading is the point of the |
|
|
|
|
|
//| TK cross in Ichimoku doctrine - an ungraded cross treats a |
|
|
|
|
|
//| counter-trend cross under the cloud as if it were a trend |
|
|
|
|
|
//| continuation above it, which is precisely the trade the |
|
|
|
|
|
//| method tells you to stand down on. |
|
|
|
|
|
//| - Kumo breakout (model 8), and the same breakout through a |
|
|
|
|
|
//| THIN cloud (model 9) - cloud thickness is Ichimoku's own |
|
|
|
|
|
//| measure of how much support/resistance is actually there, so |
|
|
|
|
|
//| a break through a thin Kumo is the higher-quality one. |
|
|
|
|
|
//| - Chikou Span confirmation (model 2): the lagging span clear |
|
|
|
|
|
//| of BOTH the price 26 periods back and the cloud at that |
|
|
|
|
|
//| point, which is the full form of the confirmation rather |
|
|
|
|
|
//| than the price-only shorthand. |
|
|
|
|
|
//| - Kijun-sen cross (model 6) and the Kijun-sen bounce (model 7) |
|
|
|
|
|
//| - the pull-back entry that the base line's "magnet" effect |
|
|
|
|
|
//| produces, which is why that model also requires the line to |
|
|
|
|
|
//| be holding its level rather than sloping against the trade. |
|
|
|
|
|
//| - Kumo twist (model 4): Senkou A actually CROSSING Senkou B |
|
|
|
|
|
//| in the projected cloud, as distinct from the cloud merely |
|
|
|
|
|
//| BEING one colour or the other (model 1). |
|
|
|
|
|
//| - Price vs the cloud (model 0), the standing trend bias every |
|
|
|
|
|
//| other reading is confirmed against. |
|
|
|
|
|
//| - Sanyaku Kouten / Sanyaku Gyakuten (model 11), the "three |
|
|
|
|
|
//| roles" alignment - Tenkan above Kijun, Chikou clear of past |
|
|
|
|
|
//| price, price clear of the cloud, all at once. Ichimoku's own |
|
|
|
|
|
//| strongest signal, hence the top weight. |
|
|
|
|
|
//| |
|
|
|
|
|
//| Pattern numbering is ordered by conviction, weakest first, so |
|
|
|
|
|
//| the highest-numbered match wins - the same convention the stock |
|
|
|
|
|
//| wizard signals use (see LongCondition() below). Weights follow |
|
|
|
|
|
//| the standard library's own scheme: the confirming STATES that |
|
|
|
|
|
//| hold across long stretches of bars (models 0-2) plus the weak |
|
|
|
|
|
//| cross grade (model 3) all sit at the 10 floor that CSignalMA, |
|
|
|
|
|
//| CSignalRSI and CSignalMACD give their Pattern_0, and the event |
|
|
|
|
|
//| models are spread across 30-100 by how much the method itself |
|
|
|
|
|
//| trusts each. Nothing between 10 and 30 - a reading either |
|
|
|
|
|
//| corroborates or it triggers. |
|
|
|
|
|
//| |
|
|
|
|
|
//| LOOKAHEAD - the single thing to get right in this class. MT5's |
|
|
|
|
|
//| iIchimoku does NOT pre-shift its buffers; it stores raw |
|
|
|
|
|
//| per-bar values and shifts only the DRAWING (Ichimoku.mq5: |
|
|
|
|
|
//| PlotIndexSetInteger(2,PLOT_SHIFT,InpKijun) for the Span A/B |
|
|
|
|
|
//| cloud plot, and (3,PLOT_SHIFT,-InpKijun) for Chikou). In |
|
|
|
|
|
//| series (reverse) indexing that means: |
|
|
|
|
|
//| - SenkouSpanA/B(i) is computed FROM bar i and is DRAWN at bar |
|
|
|
|
|
//| i-Kijun, i.e. Kijun bars into the future. So the cloud |
|
|
|
|
|
//| actually sitting under bar `idx` is SenkouSpanA/B(idx+Kijun) |
|
|
|
|
|
//| - derived from bar idx+Kijun and older, hence strictly past |
|
|
|
|
|
//| data. That +Kijun offset is what CloudTop()/CloudBottom() |
|
|
|
|
|
//| below exist to apply; reading SenkouSpanA/B(idx) as "the |
|
|
|
|
|
//| cloud here" is the classic Ichimoku backtest bug. |
|
|
|
|
|
//| - SenkouSpanA/B(idx) with NO offset is legitimate as the |
|
|
|
|
|
//| PROJECTED cloud (what the chart already draws ahead of the |
|
|
|
|
|
//| current bar) - it is computed from bar idx, so a live bar |
|
|
|
|
|
//| really does know it. Models 2 and 3 use it in exactly that |
|
|
|
|
|
//| sense, and nothing here ever indexes BELOW idx. |
|
|
|
|
|
//| - ChinkouSpan(i) is just Close(i), drawn at i+Kijun. The |
|
|
|
|
|
//| Chikou value plotted AT bar idx would be Close(idx-Kijun) - |
|
|
|
|
|
//| a bar Kijun into the FUTURE - so it is never read. The |
|
|
|
|
|
//| lookahead-free statement of the same reading is "is this |
|
|
|
|
|
//| bar's close clear of what price was Kijun bars ago", i.e. |
|
|
|
|
|
//| Close(idx) vs Close(idx+Kijun), and of the cloud that was |
|
|
|
|
|
//| plotted THERE, i.e. the spans at idx+2*Kijun. That is what |
|
|
|
|
|
//| model 9 does, and why CiIchimoku::ChinkouSpan() is |
|
|
|
|
|
//| deliberately never called anywhere in this file. |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
class CSignalIchimoku : public CExpertSignalCustom
|
|
|
|
|
{
|
|
|
|
|
protected:
|
|
|
|
|
CiIchimoku m_ichimoku; // object-indicator
|
|
|
|
|
//--- adjusted parameters
|
|
|
|
|
int m_period_tenkan; // the "Tenkan-sen period" parameter of the indicator
|
|
|
|
|
int m_period_kijun; // the "Kijun-sen period" parameter of the indicator
|
|
|
|
|
int m_period_senkou; // the "Senkou Span B period" parameter of the indicator
|
|
|
|
|
//--- "weights" of market models (0-100), numbered weakest-to-strongest so the last match in the
|
|
|
|
|
//--- if-chain is always the highest-conviction one (see the class comment). Models 0-3 are the
|
|
|
|
|
//--- CONFIRMING readings and all carry the standard-library floor weight of 10: each describes a
|
|
|
|
|
//--- standing STATE that is true across long stretches of bars rather than an event, so any of them
|
|
|
|
|
//--- alone must never approach the Min vote to open gate - they exist to corroborate an event model
|
|
|
|
|
//--- below, exactly as Pattern_0 does in CSignalMA/CSignalRSI/CSignalMACD. Models 4-11 are events
|
|
|
|
|
//--- (or, for 11, the full three-role confluence) and are spread across the same 30-100 band the
|
|
|
|
|
//--- standard library uses, ranked by how much the method itself trusts each one.
|
|
|
|
|
int m_pattern_0; // model 0 "price is on the necessary side of the cloud"
|
|
|
|
|
int m_pattern_1; // model 1 "the projected cloud is the necessary colour"
|
|
|
|
|
int m_pattern_2; // model 2 "Chikou Span confirmation (clear of past price AND cloud)"
|
|
|
|
|
int m_pattern_3; // model 3 "TK cross on the WRONG side of the cloud (weak grade)"
|
|
|
|
|
int m_pattern_4; // model 4 "Kumo twist - projected Senkou A crossed Senkou B"
|
|
|
|
|
int m_pattern_5; // model 5 "TK cross INSIDE the cloud (neutral grade)"
|
|
|
|
|
int m_pattern_6; // model 6 "price crossed Kijun-sen in the necessary direction"
|
|
|
|
|
int m_pattern_7; // model 7 "Kijun-sen bounce - pull-back to the base line, resumed"
|
|
|
|
|
int m_pattern_8; // model 8 "Kumo breakout"
|
|
|
|
|
int m_pattern_9; // model 9 "Kumo breakout through a THIN cloud"
|
|
|
|
|
int m_pattern_10; // model 10 "TK cross on the RIGHT side of the cloud (strong grade)"
|
|
|
|
|
int m_pattern_11; // model 11 "Sanyaku Kouten/Gyakuten - all three roles aligned"
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
CSignalIchimoku(void);
|
|
|
|
|
~CSignalIchimoku(void);
|
|
|
|
|
//--- methods of setting adjustable parameters
|
|
|
|
|
void PeriodTenkan(int value) { m_period_tenkan = value; }
|
|
|
|
|
void PeriodKijun(int value) { m_period_kijun = value; }
|
|
|
|
|
void PeriodSenkou(int value) { m_period_senkou = value; }
|
|
|
|
|
//--- methods of adjusting "weights" of market models
|
|
|
|
|
void Pattern_0(int value) { m_pattern_0 = value; }
|
|
|
|
|
void Pattern_1(int value) { m_pattern_1 = value; }
|
|
|
|
|
void Pattern_2(int value) { m_pattern_2 = value; }
|
|
|
|
|
void Pattern_3(int value) { m_pattern_3 = value; }
|
|
|
|
|
void Pattern_4(int value) { m_pattern_4 = value; }
|
|
|
|
|
void Pattern_5(int value) { m_pattern_5 = value; }
|
|
|
|
|
void Pattern_6(int value) { m_pattern_6 = value; }
|
|
|
|
|
void Pattern_7(int value) { m_pattern_7 = value; }
|
|
|
|
|
void Pattern_8(int value) { m_pattern_8 = value; }
|
|
|
|
|
void Pattern_9(int value) { m_pattern_9 = value; }
|
|
|
|
|
void Pattern_10(int value) { m_pattern_10 = value; }
|
|
|
|
|
void Pattern_11(int value) { m_pattern_11 = value; }
|
|
|
|
|
virtual void ApplyPatternWeight(int patternNumber, int weight);
|
|
|
|
|
//--- method of verification of settings
|
|
|
|
|
virtual bool ValidationSettings(void);
|
|
|
|
|
//--- method of creating the indicator and timeseries
|
|
|
|
|
virtual bool InitIndicators(CIndicators *indicators);
|
|
|
|
|
//--- methods of checking if the market models are formed
|
|
|
|
|
virtual int LongCondition(void);
|
|
|
|
|
virtual int ShortCondition(void);
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
//--- method of initialization of the indicator
|
|
|
|
|
bool InitIchimoku(CIndicators *indicators);
|
|
|
|
|
//--- methods of getting data
|
|
|
|
|
double Tenkan(int ind) { return(m_ichimoku.TenkanSen(ind)); }
|
|
|
|
|
double Kijun(int ind) { return(m_ichimoku.KijunSen(ind)); }
|
|
|
|
|
//--- cloud AS PLOTTED AT bar `ind` - the +m_period_kijun offset is the whole point, see the class
|
|
|
|
|
//--- comment's LOOKAHEAD note. Never call SenkouSpan*(ind) directly for a "cloud here" reading.
|
|
|
|
|
double SpanAAt(int ind) { return(m_ichimoku.SenkouSpanA(ind + m_period_kijun)); }
|
|
|
|
|
double SpanBAt(int ind) { return(m_ichimoku.SenkouSpanB(ind + m_period_kijun)); }
|
|
|
|
|
double CloudTop(int ind) { return(MathMax(SpanAAt(ind), SpanBAt(ind))); }
|
|
|
|
|
double CloudBottom(int ind) { return(MathMin(SpanAAt(ind), SpanBAt(ind))); }
|
|
|
|
|
double CloudThickness(int ind) { return(MathAbs(SpanAAt(ind) - SpanBAt(ind))); }
|
|
|
|
|
//--- PROJECTED cloud - the values the chart draws m_period_kijun bars ahead of bar `ind`, computed
|
|
|
|
|
//--- from bar `ind` itself, so a live bar genuinely has them (again, see the class comment).
|
|
|
|
|
double FutureSpanA(int ind) { return(m_ichimoku.SenkouSpanA(ind)); }
|
|
|
|
|
double FutureSpanB(int ind) { return(m_ichimoku.SenkouSpanB(ind)); }
|
|
|
|
|
//--- classification helpers shared by the long and short models
|
|
|
|
|
bool CloudIsThin(int ind);
|
fix(signals): revive a dead MA model, and demote Sanyaku from state to event
Two defects surfaced by research/test_classic.py, both verified fixed by re-running the
transcription against 178k bars of EURUSD H1.
CSignalMA model 1 could never fire. For any recursive average - and MA_TYPE_EMA is the
shipped default - MA(i) = a*Close(i) + (1-a)*MA(i+1), so
DiffMA(i) = a * (Close(i) - MA(i+1))
DiffCloseMA(i) = (1-a) * (Close(i) - MA(i+1))
are positive multiples of one quantity and always share a sign. Model 1 asks for a close
BELOW a RISING average, which is precisely the combination that identity forbids: 0.000%
of bars, either direction, any symbol. The MQL5 standard library this was ported from
defaults to MODE_SMA, where the two are merely correlated - the bug arrived with the EMA
default, not with the port. Reading the slope one bar back (DiffMAPrev) breaks the tie for
every MA type while keeping the model's stated meaning. Now fires on 7.92% of bars.
CSignalIchimoku model 11 fired on 27% of bars at weight 100. Sanyaku is three standing
STATES conjoined with no transition term, so it held across long stretches - and being
last in the if-chain at the top weight, the module's highest-conviction reading was also
its most common one, overwriting all eight event models below it on a quarter of all bars.
The old comment rejected an event form because "demanding all three flip on the same bar
would fire almost never" - true, but that is not the alternative. Kouten is the TURN: the
ALIGNMENT transitions, and only one role need change for it to. Testing !Sanyaku(idx+1)
fires once per aligned stretch. Now 2.17%, in line with Kumo breakout (2.4%) and the
strong TK cross (1.1%). DataReady() extended one bar deeper to cover the lookback.
Neither pattern showed edge before or after; this is about the models meaning what they
say and the vote not being dominated by a constant.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 17:14:34 -04:00
|
|
|
//--- the three Sanyaku roles, as reusable STATES so model 11 can test the alignment's transition
|
|
|
|
|
//--- rather than its persistence (see LongCondition()'s model 11 for why that distinction matters)
|
|
|
|
|
bool AboveCloud(int ind) { return(Close(ind) > CloudTop(ind)); }
|
|
|
|
|
bool BelowCloud(int ind) { return(Close(ind) < CloudBottom(ind)); }
|
|
|
|
|
bool ChikouClearLong(int ind) { return(Close(ind) > Close(ind + m_period_kijun) &&
|
|
|
|
|
Close(ind) > CloudTop(ind + m_period_kijun)); }
|
|
|
|
|
bool ChikouClearShort(int ind) { return(Close(ind) < Close(ind + m_period_kijun) &&
|
|
|
|
|
Close(ind) < CloudBottom(ind + m_period_kijun)); }
|
|
|
|
|
bool SanyakuLong(int ind) { return(Tenkan(ind) > Kijun(ind) && ChikouClearLong(ind) && AboveCloud(ind)); }
|
|
|
|
|
bool SanyakuShort(int ind) { return(Tenkan(ind) < Kijun(ind) && ChikouClearShort(ind) && BelowCloud(ind)); }
|
2026-07-26 18:33:12 -04:00
|
|
|
bool TKCrossUp(int ind) { return(Tenkan(ind) > Kijun(ind) && Tenkan(ind + 1) <= Kijun(ind + 1)); }
|
|
|
|
|
bool TKCrossDown(int ind) { return(Tenkan(ind) < Kijun(ind) && Tenkan(ind + 1) >= Kijun(ind + 1)); }
|
|
|
|
|
//--- true if every value the models read at `ind` is present (enough history loaded)
|
|
|
|
|
bool DataReady(int ind);
|
|
|
|
|
};
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| Constructor |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
CSignalIchimoku::CSignalIchimoku(void) : m_period_tenkan(9),
|
|
|
|
|
m_period_kijun(26),
|
|
|
|
|
m_period_senkou(52),
|
|
|
|
|
m_pattern_0(10), // confirming state - price vs the cloud
|
|
|
|
|
m_pattern_1(10), // confirming state - projected cloud colour
|
|
|
|
|
m_pattern_2(10), // confirming state - Chikou clear
|
|
|
|
|
m_pattern_3(10), // the WEAK cross grade: doctrine's "stand down", so it sits at the floor too
|
|
|
|
|
m_pattern_4(30), // Kumo twist: anticipatory, and the only event not involving price at all
|
|
|
|
|
m_pattern_5(40), // neutral cross grade - the Kumo offers no bias either way here
|
|
|
|
|
m_pattern_6(60), // Kijun cross - the same conviction CSignalMA gives its own price/level crosses
|
|
|
|
|
m_pattern_7(70), // Kijun bounce - a cross with established trend context behind it
|
|
|
|
|
m_pattern_8(80), // Kumo breakout - a structural break, not just a line cross
|
|
|
|
|
m_pattern_9(90), // ...through a thin cloud: the break the method rates most likely to hold
|
|
|
|
|
m_pattern_10(90), // the STRONG cross grade - the one Ichimoku actually wants traded
|
|
|
|
|
m_pattern_11(100) // Sanyaku: all three roles at once, the method's own top signal
|
|
|
|
|
{
|
|
|
|
|
m_id = "Ichimoku";
|
|
|
|
|
m_pattern_count = 12;
|
|
|
|
|
//--- initialization of protected data. High/Low are needed by the Kijun-sen bounce (model 6), which has
|
|
|
|
|
//--- to see the bar actually reach down to / up to the base line, not merely close near it.
|
|
|
|
|
m_used_series = USE_SERIES_HIGH + USE_SERIES_LOW + USE_SERIES_CLOSE;
|
|
|
|
|
}
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| Destructor |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
CSignalIchimoku::~CSignalIchimoku(void)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| Validation settings protected data. |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
bool CSignalIchimoku::ValidationSettings(void)
|
|
|
|
|
{
|
|
|
|
|
//--- validation settings of additional filters
|
|
|
|
|
if(!CExpertSignalCustom::ValidationSettings())
|
|
|
|
|
return(false);
|
|
|
|
|
//--- initial data checks
|
|
|
|
|
if(m_period_tenkan <= 0 || m_period_kijun <= 0 || m_period_senkou <= 0)
|
|
|
|
|
{
|
|
|
|
|
printf(__FUNCTION__ + ": all Ichimoku periods must be greater than 0");
|
|
|
|
|
return(false);
|
|
|
|
|
}
|
|
|
|
|
//--- Tenkan < Kijun < Senkou B is not cosmetic: Tenkan is meant to be the FAST line (a TK cross has no
|
|
|
|
|
//--- meaning if it is the slower of the two), and Senkou B is the widest lookback, so an inverted set
|
|
|
|
|
//--- would silently invert every model below rather than fail.
|
|
|
|
|
if(m_period_tenkan >= m_period_kijun)
|
|
|
|
|
{
|
|
|
|
|
printf(__FUNCTION__ + ": Kijun-sen period must be greater than Tenkan-sen period");
|
|
|
|
|
return(false);
|
|
|
|
|
}
|
|
|
|
|
if(m_period_kijun >= m_period_senkou)
|
|
|
|
|
{
|
|
|
|
|
printf(__FUNCTION__ + ": Senkou Span B period must be greater than Kijun-sen period");
|
|
|
|
|
return(false);
|
|
|
|
|
}
|
|
|
|
|
//--- ok
|
|
|
|
|
return(true);
|
|
|
|
|
}
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| Create indicators. |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
bool CSignalIchimoku::InitIndicators(CIndicators *indicators)
|
|
|
|
|
{
|
|
|
|
|
//--- check pointer
|
|
|
|
|
if(indicators == NULL)
|
|
|
|
|
return(false);
|
|
|
|
|
//--- initialization of indicators and timeseries of additional filters
|
|
|
|
|
if(!CExpertSignalCustom::InitIndicators(indicators))
|
|
|
|
|
return(false);
|
|
|
|
|
//--- create and initialize Ichimoku indicator
|
|
|
|
|
if(!InitIchimoku(indicators))
|
|
|
|
|
return(false);
|
|
|
|
|
//--- ok
|
|
|
|
|
return(true);
|
|
|
|
|
}
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| Initialize Ichimoku indicator. |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
bool CSignalIchimoku::InitIchimoku(CIndicators *indicators)
|
|
|
|
|
{
|
|
|
|
|
//--- check pointer
|
|
|
|
|
if(indicators == NULL)
|
|
|
|
|
return(false);
|
|
|
|
|
//--- add object to collection
|
|
|
|
|
if(!indicators.Add(GetPointer(m_ichimoku)))
|
|
|
|
|
{
|
|
|
|
|
printf(__FUNCTION__ + ": error adding object");
|
|
|
|
|
return(false);
|
|
|
|
|
}
|
|
|
|
|
//--- initialize object
|
|
|
|
|
if(!m_ichimoku.Create(m_symbol.Name(), m_period, m_period_tenkan, m_period_kijun, m_period_senkou))
|
|
|
|
|
{
|
|
|
|
|
printf(__FUNCTION__ + ": error initializing object");
|
|
|
|
|
return(false);
|
|
|
|
|
}
|
|
|
|
|
//--- ok
|
|
|
|
|
return(true);
|
|
|
|
|
}
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| Cloud thickness is Ichimoku's own measure of how much support or |
|
|
|
|
|
//| resistance the Kumo actually represents - a break through a thin |
|
|
|
|
|
//| cloud is the one the method treats as meaningful, a thick one is |
|
|
|
|
|
//| expected to absorb the attempt. "Thin" is deliberately expressed |
|
|
|
|
|
//| RELATIVE to this instrument's own recent cloud rather than as an |
|
|
|
|
|
//| absolute price distance, so the test carries across symbols and |
|
|
|
|
|
//| timeframes with no scaling constant to tune - the same reasoning |
|
|
|
|
|
//| the AI feature side applies when it ATR-normalizes thickness. |
|
|
|
|
|
//| Averaged over m_period_kijun bars, i.e. the same horizon the |
|
|
|
|
|
//| cloud is projected across. |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
bool CSignalIchimoku::CloudIsThin(int ind)
|
|
|
|
|
{
|
|
|
|
|
double sum = 0.0;
|
|
|
|
|
int count = 0;
|
|
|
|
|
for(int i = 0; i < m_period_kijun; i++)
|
|
|
|
|
{
|
|
|
|
|
double t = CloudThickness(ind + i);
|
|
|
|
|
if(t == EMPTY_VALUE)
|
|
|
|
|
break;
|
|
|
|
|
sum += t;
|
|
|
|
|
count++;
|
|
|
|
|
}
|
|
|
|
|
if(count == 0)
|
|
|
|
|
return(false);
|
|
|
|
|
double average = sum / count;
|
|
|
|
|
//--- a degenerate (zero-width) average means there is no cloud to speak of over the whole window, which
|
|
|
|
|
//--- is not the same statement as "this bar's cloud is unusually thin" - decline rather than divide.
|
|
|
|
|
if(average <= 0.0)
|
|
|
|
|
return(false);
|
|
|
|
|
return(CloudThickness(ind) < 0.5 * average);
|
|
|
|
|
}
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| Every value the models below read, checked in one place. The |
|
|
|
|
|
//| deepest read is the cloud plotted at the CHIKOU's own position |
|
|
|
|
|
//| (model 9), which is the spans at ind + 2*m_period_kijun; the |
|
|
|
|
|
//| thin-cloud average (model 8) walks a further m_period_kijun bars |
|
|
|
|
|
//| of cloud but tolerates running short on its own. Early in the |
|
|
|
|
|
//| loaded history the lines can be valid while the cloud is not, so |
|
|
|
|
|
//| one gate covers both rather than a per-value check per model. |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
bool CSignalIchimoku::DataReady(int ind)
|
|
|
|
|
{
|
|
|
|
|
if(Tenkan(ind) == EMPTY_VALUE || Tenkan(ind + 1) == EMPTY_VALUE)
|
|
|
|
|
return(false);
|
|
|
|
|
if(Kijun(ind) == EMPTY_VALUE || Kijun(ind + 1) == EMPTY_VALUE)
|
|
|
|
|
return(false);
|
|
|
|
|
if(SpanAAt(ind) == EMPTY_VALUE || SpanBAt(ind) == EMPTY_VALUE)
|
|
|
|
|
return(false);
|
|
|
|
|
if(SpanAAt(ind + 1) == EMPTY_VALUE || SpanBAt(ind + 1) == EMPTY_VALUE)
|
|
|
|
|
return(false);
|
|
|
|
|
if(FutureSpanA(ind) == EMPTY_VALUE || FutureSpanB(ind) == EMPTY_VALUE)
|
|
|
|
|
return(false);
|
|
|
|
|
if(FutureSpanA(ind + 1) == EMPTY_VALUE || FutureSpanB(ind + 1) == EMPTY_VALUE)
|
|
|
|
|
return(false);
|
fix(signals): revive a dead MA model, and demote Sanyaku from state to event
Two defects surfaced by research/test_classic.py, both verified fixed by re-running the
transcription against 178k bars of EURUSD H1.
CSignalMA model 1 could never fire. For any recursive average - and MA_TYPE_EMA is the
shipped default - MA(i) = a*Close(i) + (1-a)*MA(i+1), so
DiffMA(i) = a * (Close(i) - MA(i+1))
DiffCloseMA(i) = (1-a) * (Close(i) - MA(i+1))
are positive multiples of one quantity and always share a sign. Model 1 asks for a close
BELOW a RISING average, which is precisely the combination that identity forbids: 0.000%
of bars, either direction, any symbol. The MQL5 standard library this was ported from
defaults to MODE_SMA, where the two are merely correlated - the bug arrived with the EMA
default, not with the port. Reading the slope one bar back (DiffMAPrev) breaks the tie for
every MA type while keeping the model's stated meaning. Now fires on 7.92% of bars.
CSignalIchimoku model 11 fired on 27% of bars at weight 100. Sanyaku is three standing
STATES conjoined with no transition term, so it held across long stretches - and being
last in the if-chain at the top weight, the module's highest-conviction reading was also
its most common one, overwriting all eight event models below it on a quarter of all bars.
The old comment rejected an event form because "demanding all three flip on the same bar
would fire almost never" - true, but that is not the alternative. Kouten is the TURN: the
ALIGNMENT transitions, and only one role need change for it to. Testing !Sanyaku(idx+1)
fires once per aligned stretch. Now 2.17%, in line with Kumo breakout (2.4%) and the
strong TK cross (1.1%). DataReady() extended one bar deeper to cover the lookback.
Neither pattern showed edge before or after; this is about the models meaning what they
say and the vote not being dominated by a constant.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 17:14:34 -04:00
|
|
|
//--- the cloud plotted at the Chikou's own position, i.e. ind + 2*m_period_kijun in span terms.
|
|
|
|
|
//--- Checked at ind+1 as well: model 11 evaluates its whole alignment one bar back to detect the
|
|
|
|
|
//--- TRANSITION into Sanyaku, and that reaches one bar deeper than any other model here.
|
2026-07-26 18:33:12 -04:00
|
|
|
if(SpanAAt(ind + m_period_kijun) == EMPTY_VALUE || SpanBAt(ind + m_period_kijun) == EMPTY_VALUE)
|
|
|
|
|
return(false);
|
fix(signals): revive a dead MA model, and demote Sanyaku from state to event
Two defects surfaced by research/test_classic.py, both verified fixed by re-running the
transcription against 178k bars of EURUSD H1.
CSignalMA model 1 could never fire. For any recursive average - and MA_TYPE_EMA is the
shipped default - MA(i) = a*Close(i) + (1-a)*MA(i+1), so
DiffMA(i) = a * (Close(i) - MA(i+1))
DiffCloseMA(i) = (1-a) * (Close(i) - MA(i+1))
are positive multiples of one quantity and always share a sign. Model 1 asks for a close
BELOW a RISING average, which is precisely the combination that identity forbids: 0.000%
of bars, either direction, any symbol. The MQL5 standard library this was ported from
defaults to MODE_SMA, where the two are merely correlated - the bug arrived with the EMA
default, not with the port. Reading the slope one bar back (DiffMAPrev) breaks the tie for
every MA type while keeping the model's stated meaning. Now fires on 7.92% of bars.
CSignalIchimoku model 11 fired on 27% of bars at weight 100. Sanyaku is three standing
STATES conjoined with no transition term, so it held across long stretches - and being
last in the if-chain at the top weight, the module's highest-conviction reading was also
its most common one, overwriting all eight event models below it on a quarter of all bars.
The old comment rejected an event form because "demanding all three flip on the same bar
would fire almost never" - true, but that is not the alternative. Kouten is the TURN: the
ALIGNMENT transitions, and only one role need change for it to. Testing !Sanyaku(idx+1)
fires once per aligned stretch. Now 2.17%, in line with Kumo breakout (2.4%) and the
strong TK cross (1.1%). DataReady() extended one bar deeper to cover the lookback.
Neither pattern showed edge before or after; this is about the models meaning what they
say and the vote not being dominated by a constant.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 17:14:34 -04:00
|
|
|
if(SpanAAt(ind + 1 + m_period_kijun) == EMPTY_VALUE || SpanBAt(ind + 1 + m_period_kijun) == EMPTY_VALUE)
|
|
|
|
|
return(false);
|
2026-07-26 18:33:12 -04:00
|
|
|
if(Close(ind) == EMPTY_VALUE || Close(ind + 1) == EMPTY_VALUE)
|
|
|
|
|
return(false);
|
fix(signals): revive a dead MA model, and demote Sanyaku from state to event
Two defects surfaced by research/test_classic.py, both verified fixed by re-running the
transcription against 178k bars of EURUSD H1.
CSignalMA model 1 could never fire. For any recursive average - and MA_TYPE_EMA is the
shipped default - MA(i) = a*Close(i) + (1-a)*MA(i+1), so
DiffMA(i) = a * (Close(i) - MA(i+1))
DiffCloseMA(i) = (1-a) * (Close(i) - MA(i+1))
are positive multiples of one quantity and always share a sign. Model 1 asks for a close
BELOW a RISING average, which is precisely the combination that identity forbids: 0.000%
of bars, either direction, any symbol. The MQL5 standard library this was ported from
defaults to MODE_SMA, where the two are merely correlated - the bug arrived with the EMA
default, not with the port. Reading the slope one bar back (DiffMAPrev) breaks the tie for
every MA type while keeping the model's stated meaning. Now fires on 7.92% of bars.
CSignalIchimoku model 11 fired on 27% of bars at weight 100. Sanyaku is three standing
STATES conjoined with no transition term, so it held across long stretches - and being
last in the if-chain at the top weight, the module's highest-conviction reading was also
its most common one, overwriting all eight event models below it on a quarter of all bars.
The old comment rejected an event form because "demanding all three flip on the same bar
would fire almost never" - true, but that is not the alternative. Kouten is the TURN: the
ALIGNMENT transitions, and only one role need change for it to. Testing !Sanyaku(idx+1)
fires once per aligned stretch. Now 2.17%, in line with Kumo breakout (2.4%) and the
strong TK cross (1.1%). DataReady() extended one bar deeper to cover the lookback.
Neither pattern showed edge before or after; this is about the models meaning what they
say and the vote not being dominated by a constant.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 17:14:34 -04:00
|
|
|
if(Close(ind + m_period_kijun) == EMPTY_VALUE || Close(ind + 1 + m_period_kijun) == EMPTY_VALUE)
|
2026-07-26 18:33:12 -04:00
|
|
|
return(false);
|
|
|
|
|
if(Low(ind) == EMPTY_VALUE || High(ind) == EMPTY_VALUE)
|
|
|
|
|
return(false);
|
|
|
|
|
//--- ok
|
|
|
|
|
return(true);
|
|
|
|
|
}
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| "Voting" that price will grow. |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
int CSignalIchimoku::LongCondition(void)
|
|
|
|
|
{
|
|
|
|
|
int result = 0;
|
|
|
|
|
int idx = StartIndex();
|
|
|
|
|
if(!DataReady(idx))
|
|
|
|
|
return(0);
|
|
|
|
|
double close = Close(idx);
|
|
|
|
|
double closePrev = Close(idx + 1);
|
|
|
|
|
double kijun = Kijun(idx);
|
|
|
|
|
double kijunPrev = Kijun(idx + 1);
|
|
|
|
|
double cloudTop = CloudTop(idx);
|
|
|
|
|
double cloudBottom = CloudBottom(idx);
|
|
|
|
|
double cloudTopPrev = CloudTop(idx + 1);
|
|
|
|
|
//--- price position relative to the Kumo, the axis every graded model below is graded against
|
|
|
|
|
bool aboveCloud = (close > cloudTop);
|
|
|
|
|
bool insideCloud = (close >= cloudBottom && close <= cloudTop);
|
|
|
|
|
bool crossUp = TKCrossUp(idx);
|
|
|
|
|
//--- Chikou clear of BOTH the price Kijun bars back and the cloud plotted at that same position - the
|
|
|
|
|
//--- full form of the confirmation. Both references sit further into the PAST than this bar, never the
|
|
|
|
|
//--- future; see the class comment for why that direction is the lookahead-free one.
|
|
|
|
|
bool chikouClear = (close > Close(idx + m_period_kijun) && close > CloudTop(idx + m_period_kijun));
|
|
|
|
|
//--- every model enters at the current price. Ichimoku's own levels (Kijun, cloud edge) are the
|
|
|
|
|
//--- textbook pull-back targets, but each of these models is a BREAK/CROSS/BOUNCE that has already
|
|
|
|
|
//--- happened, so resting a limit order back at the level it just left would routinely never fill on
|
|
|
|
|
//--- the move the model voted for. Left at market for all twelve, deliberately.
|
|
|
|
|
m_base_price = 0.0;
|
|
|
|
|
//--- model 0: price is above the cloud - the standing bullish bias the stronger models confirm against,
|
|
|
|
|
//--- rather than an event in its own right.
|
|
|
|
|
if(IS_PATTERN_USAGE(0) && aboveCloud)
|
|
|
|
|
{
|
|
|
|
|
result = m_pattern_0;
|
|
|
|
|
m_active_pattern = "Pattern_0";
|
|
|
|
|
}
|
|
|
|
|
//--- model 1: the projected cloud is bullish (Senkou A above Senkou B ahead of this bar). This is the
|
|
|
|
|
//--- cloud's COLOUR - a state, not the twist event; model 4 is the event. See the class comment for why
|
|
|
|
|
//--- reading the spans unshifted here is correct and is not lookahead.
|
|
|
|
|
if(IS_PATTERN_USAGE(1) && FutureSpanA(idx) > FutureSpanB(idx))
|
|
|
|
|
{
|
|
|
|
|
result = m_pattern_1;
|
|
|
|
|
m_active_pattern = "Pattern_1";
|
|
|
|
|
}
|
|
|
|
|
//--- model 2: Chikou Span confirmation in its full form - the lagging span clear of the price Kijun
|
|
|
|
|
//--- bars back AND of the cloud that was plotted there, with price above the cloud now. Demanding, but
|
|
|
|
|
//--- still a STATE that holds for long stretches of a trend rather than an entry trigger, which is why
|
|
|
|
|
//--- it sits with the confirming models at weight 10 despite how much it asks for.
|
|
|
|
|
if(IS_PATTERN_USAGE(2) && chikouClear && aboveCloud)
|
|
|
|
|
{
|
|
|
|
|
result = m_pattern_2;
|
|
|
|
|
m_active_pattern = "Pattern_2";
|
|
|
|
|
}
|
|
|
|
|
//--- model 3: WEAK grade - a bullish TK cross occurring BELOW the cloud, i.e. against the prevailing
|
|
|
|
|
//--- Kumo bias. This is the grade Ichimoku doctrine tells you to stand down on, so it carries the same
|
|
|
|
|
//--- floor weight as the confirming states rather than being lumped in with a real cross.
|
|
|
|
|
if(IS_PATTERN_USAGE(3) && crossUp && close < cloudBottom)
|
|
|
|
|
{
|
|
|
|
|
result = m_pattern_3;
|
|
|
|
|
m_active_pattern = "Pattern_3";
|
|
|
|
|
}
|
|
|
|
|
//--- model 4: Kumo twist - Senkou A actually CROSSED above Senkou B in the projected cloud on this bar,
|
|
|
|
|
//--- the moment the future cloud changes colour. The lowest-weighted event: it is anticipatory, and the
|
|
|
|
|
//--- only model here that does not involve price at all.
|
|
|
|
|
if(IS_PATTERN_USAGE(4) && FutureSpanA(idx) > FutureSpanB(idx) && FutureSpanA(idx + 1) <= FutureSpanB(idx + 1))
|
|
|
|
|
{
|
|
|
|
|
result = m_pattern_4;
|
|
|
|
|
m_active_pattern = "Pattern_4";
|
|
|
|
|
}
|
|
|
|
|
//--- model 5: NEUTRAL grade - a bullish TK cross occurring INSIDE the cloud, where the Kumo offers no
|
|
|
|
|
//--- bias either way.
|
|
|
|
|
if(IS_PATTERN_USAGE(5) && crossUp && insideCloud)
|
|
|
|
|
{
|
|
|
|
|
result = m_pattern_5;
|
|
|
|
|
m_active_pattern = "Pattern_5";
|
|
|
|
|
}
|
|
|
|
|
//--- model 6: price crossed above the Kijun-sen - the equilibrium line, Ichimoku's nearest analogue to
|
|
|
|
|
//--- the MA cross CSignalMA votes on, and weighted to match what that signal gives its own crosses.
|
|
|
|
|
if(IS_PATTERN_USAGE(6) && close > kijun && closePrev <= kijunPrev)
|
|
|
|
|
{
|
|
|
|
|
result = m_pattern_6;
|
|
|
|
|
m_active_pattern = "Pattern_6";
|
|
|
|
|
}
|
|
|
|
|
//--- model 7: Kijun-sen bounce - price was already above the base line, dipped down to touch or pierce
|
|
|
|
|
//--- it, and closed back above. The pull-back entry the base line's magnet effect produces; requiring
|
|
|
|
|
//--- the previous close to have been above it is what separates this from the fresh cross in model 6,
|
|
|
|
|
//--- and requiring price above the cloud keeps it a trend continuation rather than a catch of a fall.
|
|
|
|
|
//--- The base line must also be flat or rising - the magnet effect is what makes this trade, and it
|
|
|
|
|
//--- only exists while the Kijun holds its level; bouncing off a FALLING base line in a long is just
|
|
|
|
|
//--- buying into a line that is coming down to meet you. Rated above the plain cross in model 6 for
|
|
|
|
|
//--- exactly that added trend context.
|
|
|
|
|
if(IS_PATTERN_USAGE(7) && aboveCloud && closePrev > kijunPrev && Low(idx) <= kijun && close > kijun &&
|
|
|
|
|
kijun >= kijunPrev)
|
|
|
|
|
{
|
|
|
|
|
result = m_pattern_7;
|
|
|
|
|
m_active_pattern = "Pattern_7";
|
|
|
|
|
}
|
|
|
|
|
//--- model 8: Kumo breakout - price closed above the cloud having not been above it on the previous bar
|
|
|
|
|
//--- (it left the cloud, or gapped over it, upward). A structural break rather than a line cross, hence
|
|
|
|
|
//--- the step up from models 6/7.
|
|
|
|
|
if(IS_PATTERN_USAGE(8) && aboveCloud && closePrev <= cloudTopPrev)
|
|
|
|
|
{
|
|
|
|
|
result = m_pattern_8;
|
|
|
|
|
m_active_pattern = "Pattern_8";
|
|
|
|
|
}
|
|
|
|
|
//--- model 9: the same breakout, but through a THIN cloud - little real resistance stood in the way, so
|
|
|
|
|
//--- Ichimoku rates the break more likely to hold than one through a thick Kumo.
|
|
|
|
|
if(IS_PATTERN_USAGE(9) && aboveCloud && closePrev <= cloudTopPrev && CloudIsThin(idx))
|
|
|
|
|
{
|
|
|
|
|
result = m_pattern_9;
|
|
|
|
|
m_active_pattern = "Pattern_9";
|
|
|
|
|
}
|
|
|
|
|
//--- model 10: STRONG grade - a bullish TK cross occurring ABOVE the cloud, so Kumo bias and trigger
|
|
|
|
|
//--- agree. The grade Ichimoku actually wants you trading.
|
|
|
|
|
if(IS_PATTERN_USAGE(10) && crossUp && aboveCloud)
|
|
|
|
|
{
|
|
|
|
|
result = m_pattern_10;
|
|
|
|
|
m_active_pattern = "Pattern_10";
|
|
|
|
|
}
|
fix(signals): revive a dead MA model, and demote Sanyaku from state to event
Two defects surfaced by research/test_classic.py, both verified fixed by re-running the
transcription against 178k bars of EURUSD H1.
CSignalMA model 1 could never fire. For any recursive average - and MA_TYPE_EMA is the
shipped default - MA(i) = a*Close(i) + (1-a)*MA(i+1), so
DiffMA(i) = a * (Close(i) - MA(i+1))
DiffCloseMA(i) = (1-a) * (Close(i) - MA(i+1))
are positive multiples of one quantity and always share a sign. Model 1 asks for a close
BELOW a RISING average, which is precisely the combination that identity forbids: 0.000%
of bars, either direction, any symbol. The MQL5 standard library this was ported from
defaults to MODE_SMA, where the two are merely correlated - the bug arrived with the EMA
default, not with the port. Reading the slope one bar back (DiffMAPrev) breaks the tie for
every MA type while keeping the model's stated meaning. Now fires on 7.92% of bars.
CSignalIchimoku model 11 fired on 27% of bars at weight 100. Sanyaku is three standing
STATES conjoined with no transition term, so it held across long stretches - and being
last in the if-chain at the top weight, the module's highest-conviction reading was also
its most common one, overwriting all eight event models below it on a quarter of all bars.
The old comment rejected an event form because "demanding all three flip on the same bar
would fire almost never" - true, but that is not the alternative. Kouten is the TURN: the
ALIGNMENT transitions, and only one role need change for it to. Testing !Sanyaku(idx+1)
fires once per aligned stretch. Now 2.17%, in line with Kumo breakout (2.4%) and the
strong TK cross (1.1%). DataReady() extended one bar deeper to cover the lookback.
Neither pattern showed edge before or after; this is about the models meaning what they
say and the vote not being dominated by a constant.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 17:14:34 -04:00
|
|
|
//--- model 11: Sanyaku Kouten - the "three roles TURNING bullish", Ichimoku's own strongest signal:
|
|
|
|
|
//--- Tenkan above Kijun, Chikou clear of past price and cloud, and price clear above the Kumo.
|
|
|
|
|
//--- This tests the bar the alignment BECOMES true, not every bar it happens to hold. The three
|
|
|
|
|
//--- conditions are standing states, so the conjunction is true across long stretches - measured at
|
|
|
|
|
//--- 27% of all bars on EURUSD H1. At weight 100, last in the chain (so it overwrites every weaker
|
|
|
|
|
//--- match) and averaged into the vote, that made the module's highest-conviction reading its most
|
|
|
|
|
//--- common one, and drowned the eight event models below it.
|
|
|
|
|
//--- The previous comment here rejected an event form on the grounds that "demanding all three flip
|
|
|
|
|
//--- on the same bar would fire almost never" - true, but that is not the alternative. Kouten means
|
|
|
|
|
//--- the turn: the ALIGNMENT is what transitions, and only one role need change for it to. Testing
|
|
|
|
|
//--- !Sanyaku(idx+1) fires exactly once per aligned stretch, which is what the doctrine describes and
|
|
|
|
|
//--- what a weight of 100 is for.
|
|
|
|
|
if(IS_PATTERN_USAGE(11) && SanyakuLong(idx) && !SanyakuLong(idx + 1))
|
2026-07-26 18:33:12 -04:00
|
|
|
{
|
|
|
|
|
result = m_pattern_11;
|
|
|
|
|
m_active_pattern = "Pattern_11";
|
|
|
|
|
}
|
|
|
|
|
if(result != 0)
|
|
|
|
|
{
|
|
|
|
|
m_active_direction = "Buy";
|
|
|
|
|
}
|
|
|
|
|
//--- return the result
|
|
|
|
|
return(result);
|
|
|
|
|
}
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| "Voting" that price will fall. |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
int CSignalIchimoku::ShortCondition(void)
|
|
|
|
|
{
|
|
|
|
|
int result = 0;
|
|
|
|
|
int idx = StartIndex();
|
|
|
|
|
if(!DataReady(idx))
|
|
|
|
|
return(0);
|
|
|
|
|
double close = Close(idx);
|
|
|
|
|
double closePrev = Close(idx + 1);
|
|
|
|
|
double kijun = Kijun(idx);
|
|
|
|
|
double kijunPrev = Kijun(idx + 1);
|
|
|
|
|
double cloudTop = CloudTop(idx);
|
|
|
|
|
double cloudBottom = CloudBottom(idx);
|
|
|
|
|
double cloudBottomPrev = CloudBottom(idx + 1);
|
|
|
|
|
bool belowCloud = (close < cloudBottom);
|
|
|
|
|
bool insideCloud = (close >= cloudBottom && close <= cloudTop);
|
|
|
|
|
bool crossDown = TKCrossDown(idx);
|
|
|
|
|
//--- mirror of LongCondition()'s chikouClear - clear BELOW past price and below the cloud plotted there
|
|
|
|
|
bool chikouClear = (close < Close(idx + m_period_kijun) && close < CloudBottom(idx + m_period_kijun));
|
|
|
|
|
//--- see LongCondition() for why every model enters at market
|
|
|
|
|
m_base_price = 0.0;
|
|
|
|
|
//--- model 0: price is below the cloud
|
|
|
|
|
if(IS_PATTERN_USAGE(0) && belowCloud)
|
|
|
|
|
{
|
|
|
|
|
result = m_pattern_0;
|
|
|
|
|
m_active_pattern = "Pattern_0";
|
|
|
|
|
}
|
|
|
|
|
//--- model 1: the projected cloud is bearish (Senkou A below Senkou B ahead of this bar) - colour, not
|
|
|
|
|
//--- the twist event; model 4 is the event
|
|
|
|
|
if(IS_PATTERN_USAGE(1) && FutureSpanA(idx) < FutureSpanB(idx))
|
|
|
|
|
{
|
|
|
|
|
result = m_pattern_1;
|
|
|
|
|
m_active_pattern = "Pattern_1";
|
|
|
|
|
}
|
|
|
|
|
//--- model 2: Chikou Span confirmation, full form - see LongCondition() for why a reading this
|
|
|
|
|
//--- demanding still sits at the confirming floor weight
|
|
|
|
|
if(IS_PATTERN_USAGE(2) && chikouClear && belowCloud)
|
|
|
|
|
{
|
|
|
|
|
result = m_pattern_2;
|
|
|
|
|
m_active_pattern = "Pattern_2";
|
|
|
|
|
}
|
|
|
|
|
//--- model 3: WEAK grade - bearish TK cross occurring ABOVE the cloud, against the prevailing bias
|
|
|
|
|
if(IS_PATTERN_USAGE(3) && crossDown && close > cloudTop)
|
|
|
|
|
{
|
|
|
|
|
result = m_pattern_3;
|
|
|
|
|
m_active_pattern = "Pattern_3";
|
|
|
|
|
}
|
|
|
|
|
//--- model 4: Kumo twist - Senkou A crossed BELOW Senkou B in the projected cloud on this bar
|
|
|
|
|
if(IS_PATTERN_USAGE(4) && FutureSpanA(idx) < FutureSpanB(idx) && FutureSpanA(idx + 1) >= FutureSpanB(idx + 1))
|
|
|
|
|
{
|
|
|
|
|
result = m_pattern_4;
|
|
|
|
|
m_active_pattern = "Pattern_4";
|
|
|
|
|
}
|
|
|
|
|
//--- model 5: NEUTRAL grade - bearish TK cross occurring INSIDE the cloud
|
|
|
|
|
if(IS_PATTERN_USAGE(5) && crossDown && insideCloud)
|
|
|
|
|
{
|
|
|
|
|
result = m_pattern_5;
|
|
|
|
|
m_active_pattern = "Pattern_5";
|
|
|
|
|
}
|
|
|
|
|
//--- model 6: price crossed below the Kijun-sen
|
|
|
|
|
if(IS_PATTERN_USAGE(6) && close < kijun && closePrev >= kijunPrev)
|
|
|
|
|
{
|
|
|
|
|
result = m_pattern_6;
|
|
|
|
|
m_active_pattern = "Pattern_6";
|
|
|
|
|
}
|
|
|
|
|
//--- model 7: Kijun-sen bounce - price was already below the base line, rallied up to touch or pierce
|
|
|
|
|
//--- it, and closed back below, with the base line flat or falling. See LongCondition()'s model 7 for
|
|
|
|
|
//--- why the slope condition is part of the model rather than a weight adjustment.
|
|
|
|
|
if(IS_PATTERN_USAGE(7) && belowCloud && closePrev < kijunPrev && High(idx) >= kijun && close < kijun &&
|
|
|
|
|
kijun <= kijunPrev)
|
|
|
|
|
{
|
|
|
|
|
result = m_pattern_7;
|
|
|
|
|
m_active_pattern = "Pattern_7";
|
|
|
|
|
}
|
|
|
|
|
//--- model 8: Kumo breakout - price closed below the cloud having not been below it on the previous bar
|
|
|
|
|
if(IS_PATTERN_USAGE(8) && belowCloud && closePrev >= cloudBottomPrev)
|
|
|
|
|
{
|
|
|
|
|
result = m_pattern_8;
|
|
|
|
|
m_active_pattern = "Pattern_8";
|
|
|
|
|
}
|
|
|
|
|
//--- model 9: the same breakout through a THIN cloud
|
|
|
|
|
if(IS_PATTERN_USAGE(9) && belowCloud && closePrev >= cloudBottomPrev && CloudIsThin(idx))
|
|
|
|
|
{
|
|
|
|
|
result = m_pattern_9;
|
|
|
|
|
m_active_pattern = "Pattern_9";
|
|
|
|
|
}
|
|
|
|
|
//--- model 10: STRONG grade - bearish TK cross occurring BELOW the cloud
|
|
|
|
|
if(IS_PATTERN_USAGE(10) && crossDown && belowCloud)
|
|
|
|
|
{
|
|
|
|
|
result = m_pattern_10;
|
|
|
|
|
m_active_pattern = "Pattern_10";
|
|
|
|
|
}
|
|
|
|
|
//--- model 11: Sanyaku Gyakuten - the bearish "three roles" alignment
|
fix(signals): revive a dead MA model, and demote Sanyaku from state to event
Two defects surfaced by research/test_classic.py, both verified fixed by re-running the
transcription against 178k bars of EURUSD H1.
CSignalMA model 1 could never fire. For any recursive average - and MA_TYPE_EMA is the
shipped default - MA(i) = a*Close(i) + (1-a)*MA(i+1), so
DiffMA(i) = a * (Close(i) - MA(i+1))
DiffCloseMA(i) = (1-a) * (Close(i) - MA(i+1))
are positive multiples of one quantity and always share a sign. Model 1 asks for a close
BELOW a RISING average, which is precisely the combination that identity forbids: 0.000%
of bars, either direction, any symbol. The MQL5 standard library this was ported from
defaults to MODE_SMA, where the two are merely correlated - the bug arrived with the EMA
default, not with the port. Reading the slope one bar back (DiffMAPrev) breaks the tie for
every MA type while keeping the model's stated meaning. Now fires on 7.92% of bars.
CSignalIchimoku model 11 fired on 27% of bars at weight 100. Sanyaku is three standing
STATES conjoined with no transition term, so it held across long stretches - and being
last in the if-chain at the top weight, the module's highest-conviction reading was also
its most common one, overwriting all eight event models below it on a quarter of all bars.
The old comment rejected an event form because "demanding all three flip on the same bar
would fire almost never" - true, but that is not the alternative. Kouten is the TURN: the
ALIGNMENT transitions, and only one role need change for it to. Testing !Sanyaku(idx+1)
fires once per aligned stretch. Now 2.17%, in line with Kumo breakout (2.4%) and the
strong TK cross (1.1%). DataReady() extended one bar deeper to cover the lookback.
Neither pattern showed edge before or after; this is about the models meaning what they
say and the vote not being dominated by a constant.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 17:14:34 -04:00
|
|
|
//--- Sanyaku Gyakuten - mirror of model 11 long, and an EVENT for the same reason (see there)
|
|
|
|
|
if(IS_PATTERN_USAGE(11) && SanyakuShort(idx) && !SanyakuShort(idx + 1))
|
2026-07-26 18:33:12 -04:00
|
|
|
{
|
|
|
|
|
result = m_pattern_11;
|
|
|
|
|
m_active_pattern = "Pattern_11";
|
|
|
|
|
}
|
|
|
|
|
if(result != 0)
|
|
|
|
|
{
|
|
|
|
|
m_active_direction = "Sell";
|
|
|
|
|
}
|
|
|
|
|
//--- return the result
|
|
|
|
|
return(result);
|
|
|
|
|
}
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| Set the specified pattern's weight to the specified value |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
void CSignalIchimoku::ApplyPatternWeight(int patternNumber, int weight)
|
|
|
|
|
{
|
|
|
|
|
switch(patternNumber)
|
|
|
|
|
{
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
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;
|
|
|
|
|
case 5:
|
|
|
|
|
Pattern_5(weight);
|
|
|
|
|
break;
|
|
|
|
|
case 6:
|
|
|
|
|
Pattern_6(weight);
|
|
|
|
|
break;
|
|
|
|
|
case 7:
|
|
|
|
|
Pattern_7(weight);
|
|
|
|
|
break;
|
|
|
|
|
case 8:
|
|
|
|
|
Pattern_8(weight);
|
|
|
|
|
break;
|
|
|
|
|
case 9:
|
|
|
|
|
Pattern_9(weight);
|
|
|
|
|
break;
|
|
|
|
|
case 10:
|
|
|
|
|
Pattern_10(weight);
|
|
|
|
|
break;
|
|
|
|
|
case 11:
|
|
|
|
|
Pattern_11(weight);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//+------------------------------------------------------------------+
|