//+------------------------------------------------------------------+ //| WarriorEnums.mqh | //| AnimateDread | //| | //| EVERY INPUT THIS EA TAKES IS AN ENUM, and each enum's VALUE IS | //| ITS PAYLOAD. SL_ATR_x2 is literally 2, RISK_PCT_3 is literally 3, | //| so a consumer writes `m_atr * SL_Mode` with no lookup table and | //| no switch that can fall out of step with the list. The MT5 | //| optimizer steps over members, so a sweep can only ever produce a | //| legal configuration - which is the real reason for the dropdowns. | //| | //| ORDINALS ARE PINNED AND NEVER REUSED. MT5 stores an input's VALUE | //| in the .set file and in each chart's .chr, and does not validate | //| it against the current enum. Renumbering a member therefore | //| silently re-points every saved configuration at a different | //| setting. Gaps in the sequence are deliberate headstones for | //| members that were removed; leave them. | //+------------------------------------------------------------------+ #ifndef WARRIOR_SIMPLE_ENUMS_MQH #define WARRIOR_SIMPLE_ENUMS_MQH //--- Which way this chart is allowed to trade. LONG_ONLY exists because an index is not symmetric; //--- it is a legitimate setting, not a crutch. Value 1 was the default a stale tester preset once //--- supplied to every run, turning a two-sided EA long-only for days, so read the init echo. enum WARRIOR_DIRECTION { DIR_BOTH = 0, // Both directions DIR_LONG = 1, // Long only DIR_SHORT = 2, // Short only }; //--- Position sizing. 1 is deliberately vacant: it was INTELLIGENT, which staked real money on an //--- uncalibrated confidence number (and in an earlier form increased size after a losing streak). //--- It is not coming back, and the hole stops a saved "1" from selecting something else. enum WARRIOR_MONEY_MODE { MONEY_FIXED_RISK = 0, // Risk a fixed % of balance MONEY_FIXED_LOT = 2, // Fixed lot size }; //--- Risk per trade, as a whole percent of balance. The value IS the percent. enum WARRIOR_RISK_PCT { RISK_1 = 1, // 1% RISK_2 = 2, // 2% RISK_3 = 3, // 3% RISK_5 = 5, // 5% }; //--- The stop, in ATR from entry. The value IS the multiple. enum WARRIOR_SL_MODE { SL_ATR_x1 = 1, // ATR x 1 SL_ATR_x2 = 2, // ATR x 2 SL_ATR_x3 = 3, // ATR x 3 SL_ATR_x4 = 4, // ATR x 4 }; //--- The target, in ATR from entry. 0 = none, run it on the trail alone. enum WARRIOR_TP_MODE { TP_NONE = 0, // No target (trail only) TP_ATR_x1 = 1, // ATR x 1 TP_ATR_x2 = 2, // ATR x 2 TP_ATR_x3 = 3, // ATR x 3 TP_ATR_x4 = 4, // ATR x 4 TP_ATR_x6 = 6, // ATR x 6 TP_ATR_x8 = 8, // ATR x 8 TP_ATR_x10 = 10, // ATR x 10 }; //--- The trailing stop, in ATR behind price. The value IS the multiple; 0 disables it. enum WARRIOR_TRAIL_MODE { TRAIL_NONE = 0, // No trailing stop TRAIL_ATR_x1 = 1, // Trail at ATR x 1 TRAIL_ATR_x2 = 2, // Trail at ATR x 2 TRAIL_ATR_x3 = 3, // Trail at ATR x 3 }; //--- THE VOTE THRESHOLD, as a percent of the ensemble's weight. //--- //--- ⚠ WHAT THIS MEANS DEPENDS ON THE ROSTER, and that is the single easiest way to misread this EA. //--- CExpertSignal::Direction() divides the weighted sum by the NUMBER OF FILTERS THAT ANSWERED, so //--- one unopposed voter at full weight scores 100/N. With 19 filters registered that is 5.3%, and a //--- threshold of 15% therefore demands three agreeing voters, not one. Change the roster and every //--- rung on this list means something different. The EA prints the resolved ladder at init for //--- exactly this reason - read that, not this comment. //--- //--- The sub-5% rungs exist because a large roster pushes the whole useful range down there. enum WARRIOR_THRESHOLD { THR_1 = 1, // 1% THR_2 = 2, // 2% THR_3 = 3, // 3% THR_4 = 4, // 4% THR_5 = 5, // 5% THR_10 = 10, // 10% THR_15 = 15, // 15% THR_20 = 20, // 20% THR_25 = 25, // 25% THR_30 = 30, // 30% THR_40 = 40, // 40% THR_50 = 50, // 50% }; //--- THE PROBABILITY CUT for anything that outputs a calibrated probability - the neural module. //--- Stored as integer percent, read as value/100.0. //--- //--- 50 IS "NO CUT" AND IS THE RIGHT DEFAULT until a trained model's calibration has been measured //--- on the instrument it will trade. A threshold chosen before a calibration curve exists is a //--- guess wearing a setting's clothes, and it will look like a decision in the .set file forever. //--- //--- ⚠ FOR THE FRACTAL NET, EXPECT THE USEFUL CUT TO BE LOW, and to act as a floor rather than a //--- trigger: measured mean R by predicted-probability quintile was -0.230 / -0.089 / -0.026 / //--- +0.002 / +0.017 across 20 series. Nearly all of the separation is in refusing the bottom, not //--- in selecting the top - so raising this hunting for a "high conviction" band is chasing a part //--- of the curve that was measured flat. enum WARRIOR_CONFIDENCE { CONF_50 = 50, // 0.50 - no cut CONF_55 = 55, // 0.55 CONF_60 = 60, // 0.60 CONF_65 = 65, // 0.65 CONF_70 = 70, // 0.70 CONF_75 = 75, // 0.75 CONF_80 = 80, // 0.80 CONF_90 = 90, // 0.90 }; //--- A MODULE'S WEIGHT IN THE VOTE, as a percent. The value IS the percent, so WEIGHT_100 is 1.0. //--- //--- These are SWEPT BY THE OPTIMISER, alongside the threshold and the ATR multiples, and that is //--- the deliberate division of labour with the database: the journal sets the 49 PATTERN weights //--- from measured expectancy (far too many to optimise), the optimiser sets the 12 MODULE weights //--- (few enough to be tractable, and coarse enough that a genetic pass can explore them). //--- //--- WEIGHT_0 IS THE USEFUL ONE. A module at zero is switched off without being deleted, so the //--- optimiser can discover that an indicator contributes nothing - which is the question this EA //--- has never been able to ask, because every module has always voted at weight 1.0 by default. enum WARRIOR_WEIGHT { WEIGHT_0 = 0, // 0.0 - silent WEIGHT_25 = 25, // 0.25 WEIGHT_50 = 50, // 0.50 WEIGHT_75 = 75, // 0.75 WEIGHT_100 = 100, // 1.00 - the default WEIGHT_150 = 150, // 1.50 WEIGHT_200 = 200, // 2.00 }; //--- MOVE THE STOP TO ENTRY once the trade is this many TENTHS of R in front. The value IS the //--- tenths, so BE_AT_0R5 is 5 and the consumer divides by 10. //--- //--- ⚠ THIS IS NOT A TRAILING STOP AND MUST NOT BE CONFUSED WITH ONE. Measured 2026-09-11: every //--- ATR-trail setting made results WORSE (+150.67 -> +90.56 at 1 ATR, worse as it widened), //--- because a trail keeps moving and exits the winner on its first pullback. Breakeven moves //--- ONCE and then stands still, so it scratches the loser without capping the winner. On 5,491 //--- traded-side firings the counterfactual was mean R -0.132 -> +0.216 at +0.5R. enum WARRIOR_BREAKEVEN { BE_OFF = 0, // Never move the stop to entry BE_AT_0R5 = 5, // +0.5 R BE_AT_0R7 = 7, // +0.7 R BE_AT_1R0 = 10, // +1.0 R BE_AT_1R5 = 15, // +1.5 R }; //--- MANAGEMENT MODEL CUT. At +0.5R the model is asked "does this continue?"; below this //--- probability the trade is closed at the crossing instead of being left to the stop. The value //--- IS the percent. MGMT_OFF disables both the model and its training walk. //--- //--- ⚠ 46% of crossings continue and 54% retrace, so a cut of 50 acts on almost every trade while //--- a cut of 30 acts only where the model is confident. Which is right depends on the model's //--- calibration, which is why this is an input and not a constant - and why the net prints its //--- held-out AUC: a cut applied to a coin-flip model is just a random early exit. enum WARRIOR_MGMT_CUT { MGMT_OFF = 0, // No management model MGMT_CUT30 = 30, // exit when P(continue) < 0.30 MGMT_CUT40 = 40, // < 0.40 MGMT_CUT50 = 50, // < 0.50 MGMT_CUT60 = 60, // < 0.60 }; //--- FADE THE CROWD. When at least this many filters vote the SAME way, take the OTHER side; when //--- fewer do, stand aside entirely. The value IS the voter count. //--- //--- WHY THIS EXISTS. Measured on 32,409 traded bar-sides (4 majors, H4, 2015-2026) the ensemble's //--- conviction is monotonically ANTI-predictive: agree=12 -0.27R, agree=13 -0.61R, in both halves, //--- on every symbol. Priced exactly from the journal as a symmetric-1R fade (wins iff the traded //--- side touched -1R before +1R, read from mfeR, ties scored AGAINST the fade): agree>=12 gives //--- +0.294R in-sample and +0.323R out of sample, every symbol, every t >= 3.5. The mechanism is //--- plain: these are lagging indicators, the vote fires after the move, and when ALL of them agree //--- the move is mature. Unanimity is exhaustion. //--- USE WITH StopMode == TargetMode (1R/1R). The measurement was symmetric; an asymmetric fade is //--- a different trade that has not been priced. enum WARRIOR_FADE { FADE_OFF = 0, // Normal voting FADE_AGREE_11 = 11, // Fade when >= 11 filters agree (+0.15R measured) FADE_AGREE_12 = 12, // Fade when >= 12 agree (+0.29R measured) FADE_AGREE_13 = 13, // Fade only unanimity (+0.6R measured, rare) }; //--- THE DIP-BUY'S TWO MEASURED FORMS (Signals\SignalDipBuy.mqh has the numbers): the daily RSI(2) //--- Connors form, and the z-score form that the seven-style scan found to be the deepest and the //--- only one with H4 cadence (~15 trades a month on SP500). enum WARRIOR_DIP_ENTRY { DIP_RSI2 = 0, // RSI(2) at or below RsiEntry (the daily Connors form) DIP_ZSCORE = 1, // close below the 20-bar mean by DipZ standard deviations }; #endif // WARRIOR_SIMPLE_ENUMS_MQH