Warrior_EA/Enumerations/WarriorEnums.mqh
AnimateDread 47a5ef338b Refactor Warrior EA: Integrate custom signal modules, enhance voting mechanism, and improve management features
- 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.
2026-09-13 14:32:40 -04:00

209 lines
9.7 KiB
MQL5

//+------------------------------------------------------------------+
//| 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