//+------------------------------------------------------------------+ //| Inputs.mqh | //| AnimateDread | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "AnimateDread" #property link "https://www.mql5.com" #include "..\Enumerations\InputEnums.mqh" //--- Each `input string *_Settings` is a GUI-only section divider: MetaTrader renders an input string //--- whose value equals its comment as a header. Never read by code. //--- NN Optimizer / Performance must stay LAST - AI\Network.mqh's Adam/Sgd inputs render after it. //================================================================================================== // GENERAL //================================================================================================== input string Expert_Settings = "General"; // General //--- 0 = ASSIGN ONE AND REMEMBER IT. On first attach the EA draws a random magic, writes it to //--- MQL5\Files\Warrior__.magic, and reads that same value back on every later start - //--- so it is unique without anyone typing it, and STABLE, which is the part that matters: the magic //--- is how the EA recognises its own positions. A magic that changed on restart would leave every //--- open position invisible to the close-all, the risk-budget flatten and the journal - trades still //--- running that no code would ever manage again. //--- Set a non-zero value to pin one explicitly instead (back-compat; a chart already carrying 2024 //--- keeps it, because MT5 stores inputs per chart and an existing attach never sees this default). input ulong Expert_MagicNumber = 0; // Magic number (0 = assign + remember automatically) input bool Expert_EveryTick = false; // Calculate on every tick //--- Also throttles the per-era training journal: false prints each diagnostic on the first eras and //--- then every TRAIN_LOG_EVERY_ERAS-th (state CHANGES always print). true is the full firehose. input bool VerboseMode = false; // Verbose journal + detailed panel (full per-era logs) //--- Dev diagnostics to the Experts journal (plateau stage, deploy gate, selection internals). const bool DebuggingMode = false; //--- Pins the dense-taper depth instead of deriving it (ComputeHiddenLayerCount). 0 = derived, the only //--- value that should ship. Compile-time, so two forced depths cannot run from one .ex5. const int ForceHiddenLayers = 0; //================================================================================================== // MONEY MANAGEMENT //================================================================================================== input string MM_Settings = "Money Management"; // Money Management input MONEY_MANAGEMENT_STRATEGY MM_STRATEGY = FIXED_RISK; // MM strategy input MONEY_RISK_PERCENT_PRESET Money_Risk_Percent = RISK_PCT_1; // Risk % of balance per trade input double Money_FixLot_Lots = 0.01; // Fixed lot size [0.01-10] //================================================================================================== // TRADE MANAGEMENT (entry / stop / target / trailing / exit) //================================================================================================== input string Entry_Settings = "Trade Management"; // Trade Management //--- TRADE MANAGEMENT IS THE TESTER GA'S SEARCH SPACE (2026-08-24). The NN's job is the swing label; //--- none of these touch a fingerprint or a DB key, so the GA can sweep them without a retrain. input TRADING_DIRECTION tradingdirection = BOTH; // Trade direction //--- TWO BOOKS, ONE PER SIDE (2026-08-26). ON, and on a RETAIL_HEDGING account, the EA keeps an //--- independent long book and short book on this symbol: at most one long and at most one short, //--- each opened on its own side's vote and each held to its own barrier. OFF, or on a NETTING //--- account, behaviour is exactly as before - one position per symbol, opposite votes ignored. //--- //--- WHY THIS AND NOT A VOTE EXIT. The deploy gate certifies P(label agrees | the vote fired) and //--- the label runs to the barrier. Closing early on a reversal vote makes the realised outcome stop //--- being the labelled one, so the certified precision no longer describes what is traded. Opening //--- the OTHER side instead acts on the new signal while leaving the old position's certification //--- intact, and it costs no more than closing-then-reversing would: both pay the new side's spread, //--- and the only difference is that the existing position runs on to the barrier its own gate //--- already measured as positive-expectancy. That is why Signal_ThresholdClose could be deleted //--- rather than tuned - see the ensemble deploy gate. //--- //--- ALLOWED AT THE5ERS - single-account hedging is permitted; what their #12/#17 ban is hedging //--- ACROSS accounts or firms (hedge arbitrage, inter-account, cross-firm). Correction recorded //--- 2026-08-26 after an earlier reading of #17 wrongly caught this case. //--- //--- NOT in BuildModelFingerprint(): no .nnw is re-keyed by turning this on or off. input bool Allow_Hedging = true; // Hedging: independent long + short book (max 1 each) input ENTRY_MULTIPLIER Entry_Multiplier = MARKET; // Entry type/offset input STOP_LOSS_MODE SL_Mode = SL_ATR_x2; // Stop-loss mode input TAKE_PROFIT_MODE TP_Mode = TP_ATR_x6; // Take-profit mode input TRAILING_STRATEGY TrailingStrategy = TRAILING_STRATEGY_NONE; // Trailing stop input BARS_EXPIRATION Signal_Expiration = BARS_X3; // Pending order expiry (bars) //--- Confidence_Source WAS REMOVED 2026-08-25 together with all five confidence-scaled trade-management //--- modes it fed (Intelligent entry / SL / TP / trailing / lot size). See CONFIDENCE_SOURCE's removal //--- note in Enumerations\InputEnums.mqh. Trade management is now entirely explicit: what the GA sets //--- is what the trade gets, which is also what makes a GA sweep of it interpretable. //--- CExpertSignal::m_threshold_open / m_threshold_close, on the library's own 0-100 scale: the //--- vote is a WEIGHTED MEAN of the firing patterns' weights, which cannot exceed 100. //--- //--- THIS IS A CONSENSUS RULE IN DISGUISE, and its meaning moves with the win rate. The vote is //--- sum(moduleWeight x tierWeight x sign) / sum(moduleWeight over every member that EVALUATED the //--- bar - abstentions included, by design since 2026-08-19). So with N members of similar weight //--- the reachable votes are quantised by how many agree, and the threshold picks the quorum: //--- //--- 4 members, tier weight ~30 (the pivot-event label's win rate): //--- 4 agree -> 30 PCT_25 => needs 4 of 4 (UNANIMITY) //--- 3 agree, 1 abstain -> 22.5 PCT_20 => needs 3 of 4 //--- 2 agree, 2 abstain -> 15 PCT_15 => needs 2 of 4 //--- //--- PCT_25 was correct while the direction-to-next-pivot label produced ~70% win rates: the //--- ceiling was ~70 and 25 asked for about a third of it. Under the pivot-event label the win //--- rates are ~30%, so 25 sits at ~83% of the ceiling and has silently become a UNANIMITY rule. //--- Measured 2026-08-26: every one of the 6 symbols cleared its precision bar and 4 of 6 failed //--- ONLY on coverage, which fell 6.8% -> 2.2% over 35 eras as the four models specialised and //--- unanimity got rarer. That also feeds a doom loop - fewer fires shrink effN, which RAISES the //--- exact-binomial deploy bar (SP500: 24.1% -> 32.9% at FLAT precision). //--- //--- THIS IS NOW ONLY A SEED (2026-08-26). The era verdict DERIVES the threshold - the highest rung //--- whose vote still clears the whole deploy gate - and publishes it to the live signal every tick //--- (THE DERIVED THRESHOLD in Expert\AIBase\Training.mqh; CExpertCustom::PublishVoteThreshold). //--- The value below is read once, and only governs the bars traded BEFORE the first era has been //--- scored. Setting it per chart is no longer necessary and no longer meaningful. //--- //--- WHY IT HAD TO STOP BEING AN INPUT. Two independent reasons, both measured: //--- 1. THERE IS NO GOOD GLOBAL VALUE. The right rung differs per symbol AND drifts per era. On //--- 619 era verdicts across the six live charts, EVERY era had at least one rung clearing the //--- full gate - while at the fixed 25% the fleet was actually running, four of six symbols had //--- none, ever. The models were deployable the whole time; the constant was the blocker. //--- 2. AN INPUT CANNOT BE CORRECTED. MT5 stores an input's value PER CHART in //--- profiles\Charts\*\chart*.chr. The live fleet kept running at 25 across a full //--- close/recompile/relaunch cycle with the log still reading "fired at vote>=25%" - changing //--- the default here moved nothing. A number that can only be fixed by hand-editing six charts //--- is not a parameter, it is a liability. //--- //--- The knob that remains is MIN_COVERAGE_FRACTION_OF_BASE_RATE (ExpertSignalAIBase.mqh) - "how //--- much of the market must I catch before I believe the measurement". That is the real policy //--- question, and it is one question rather than six per-chart ones. //--- //--- NOT in BuildModelFingerprint(), so none of this re-keys a trained .nnw. input PERCENTAGE_PRESETS Signal_ThresholdOpen = PCT_15; // Vote threshold SEED (derived after era 1) //--- CLOSE ON THE OPPOSITE VOTE. Signal_ThresholdClose (and its SIGNAL_CLOSE_PRESETS enum) was //--- replaced by this boolean 2026-08-26: a second THRESHOLD was always redundant, because "the bot //--- now says the other way" is one question, not two. When this is ON the exit fires at the SAME //--- derived threshold the entry uses, published to the signal by //--- CExpertCustom::PublishVoteThreshold() - so there is still nothing to tune. //--- //--- OFF IS THE DEFAULT, AND THE REASON IS STATISTICAL, NOT A PREFERENCE. The deploy gate certifies //--- P(label agrees | the vote fired), and the label runs to the barrier. Close early and the //--- realised outcome is no longer the labelled one, so the certified precision stops describing what //--- is actually being traded. Turning this on is a DIFFERENT strategy from the one the gate //--- measured, and it has not been measured. Treat any win rate on the panel with suspicion until it //--- has been. //--- //--- HOW IT COMPOSES WITH Allow_Hedging - they are alternative reversal policies, not independent: //--- hedging ON, exit OFF (default) -> the opposite vote OPENS the other book; both positions run //--- to their own barriers, both stay certified. //--- hedging ON, exit ON -> the long book closes and the short book opens on the same //--- pass, so this is classic reverse behaviour and a hedge //--- never actually forms. //--- hedging OFF, exit ON -> plain close-on-reversal on the single position. //--- hedging OFF, exit OFF -> hold to the barrier, opposite votes ignored entirely. //--- //--- It drives CExpertSignalCustom::m_holdToBarrier, which until now NOTHING EVER SET - the whole //--- hold-to-barrier mechanism was dormant and the disabled close threshold was doing the work alone. input bool Exit_On_Reversal_Vote = false; // Close on opposite vote (default: hold to the barrier) //--- OFF = the filtered view, one arrow per position the EA would open (vote + ranking + threshold //--- applied). ON = every model's raw opinion, per model - the diagnostic view that shows a collapsed //--- member the filtered view cannot, because a collapsed member simply stops appearing in it. input bool DrawUnfilteredSignals = false; // Draw raw per-model signals (bypass vote/ranking/threshold) //================================================================================================== // INDICATOR SEEDS (the AI feature block's starting periods) //================================================================================================== //--- THE FOUR CLASSIC VOTES WERE REMOVED 2026-08-24 (EnableMA / EnableRSI / EnableMACD / //--- EnableIchimoku, and the Classic_Shift input that only they read). All 26 shipped patterns were //--- measured as entries on 178k-bar histories across four instruments and three barrier geometries: //--- nothing separated from chance individually, by vote threshold, by quorum, or as event plus //--- confirmation, and the two bars of lookahead that had once produced a +4 sigma reading were the //--- whole of it. All four inputs had shipped false ever since, so this removes dormant code, not //--- behaviour. The seeds below stay because the AI FEATURE block still reads them. //--- SEEDS ONLY. All indicator parameters are tuner-owned: the auto-tuner searches from these under a //--- family-wise gate and persists winners in TunedPeriods_{SYM}_{TF}.cfg, which the AI features read. //--- Hand-setting means editing these constants, which deliberately bypasses that gate. const MA_PERIOD_PRESETS PeriodMA = MA_PERIOD_50; // MA period seed const MA_TYPE_PRESETS MA_Type = MA_TYPE_SMA; // MA type seed const RSI_PERIOD_PRESETS PeriodRSI = RSI_PERIOD_14; // RSI period seed const MACD_FAST_PRESETS MACD_PeriodFast = MACD_FAST_12; const MACD_SLOW_PRESETS MACD_PeriodSlow = MACD_SLOW_26; const MACD_SIGNAL_PRESETS MACD_PeriodSignal = MACD_SIGNAL_9; const ICHIMOKU_TENKAN_PRESETS Ichimoku_PeriodTenkan = ICHI_TENKAN_9; const ICHIMOKU_KIJUN_PRESETS Ichimoku_PeriodKijun = ICHI_KIJUN_26; const ICHIMOKU_SENKOU_PRESETS Ichimoku_PeriodSenkou = ICHI_SENKOU_52; //================================================================================================== // NEURAL NETWORK (training) //================================================================================================== input string NNetworks_Settings = "Neural Networks"; // Neural Networks //--- Two or more enabled = an ensemble (|ENS1 fingerprint token + joint vote-level deploy gate); //--- exactly one = solo, same fingerprint and files as the old preset; none = classic only. Every //--- enabled NN trains a net per chart, so prefer fewer members on sub-daily timeframes. input bool Use_MLP = true; // NN vote: MLP (dense) input bool Use_CONV = true; // NN vote: CONV (convolutional) input bool Use_LSTM = true; // NN vote: LSTM (recurrent) input bool Use_CONVLSTM = true; // NN vote: CONVLSTM (conv front-end + LSTM) //--- One-shot measurement: an Alglib forest, MLP and OLS fit on the net's OWN windows, labels, split and //--- gate arithmetic. Answers whether a flat result is the architecture or the matrix. Nothing trades on //--- it and no model is saved. See Expert\Training\BaselineComparator.mqh. input bool Run_Alglib_Baselines = true; // Diagnostic: forest + linear on the NN's own matrix //--- CROSS-INSTRUMENT TRAINING ROWS. Each chart publishes its own feature rows and adopts its peers', //--- so one net trains on several instruments at once while every chart keeps its own model. Measured //--- +2.02pp of paired skill at H4 (t_mkt 3.97, clearing its family-wise bar) and replicated at D1; //--- the per-instrument arm was NEGATIVE on every feature set. Only peers whose MODEL FINGERPRINT //--- matches contribute, so it does nothing until a second chart runs the same configuration. //--- Deliberately NOT a fingerprint member: it changes what the model trains on, not what it is. input bool Use_Training_Pool = true; // Train on peer charts' rows as well as this chart's //--- WHAT THE DIRECTION MODELS LEARN: the swing-pivot direction label, unconditionally. The label //--- is geometry-free - it only says which way the next confirmed pivot lies - which is what leaves //--- trade management to the tester GA instead of baking it into what the net learns. //+------------------------------------------------------------------+ //| Roster string for logs and the journal's filterID column. Lives | //| here because TradeJournalManager.mqh is included before | //| Variables.mqh's globals and needs it too. | //+------------------------------------------------------------------+ string EnabledNNSummary() { string s = ""; if(Use_MLP) s += (StringLen(s) > 0 ? "+MLP" : "MLP"); if(Use_CONV) s += (StringLen(s) > 0 ? "+CONV" : "CONV"); if(Use_LSTM) s += (StringLen(s) > 0 ? "+LSTM" : "LSTM"); if(Use_CONVLSTM) s += (StringLen(s) > 0 ? "+CONVLSTM" : "CONVLSTM"); if(StringLen(s) <= 0) s = "Classic"; return s; } input ENUM_OPTIMIZATION TrainingOptimizer = ADAM; // Weight optimizer //--- The target is 3-way (Buy/Sell/Neutral), so the head is a 3-class softmax. The regression path //--- stays implemented but is no longer selectable. const OUTPUT_NEURONS_COUNT OutputNeuronsCount = OUTPUT_CLASSIFICATION; //--- First-layer width, LSTM hidden size, conv filter count, taper depth and reduction are all //--- DERIVED from the post-selection input width and the in-sample bar count - see //--- ComputeFirstLayerWidth(), ComputeConvFilterCount(), ComputeLstmHiddenSize(). const bool EnableBatchNorm = true; // AI: batch normalization //--- EMA window for the running mean/variance, in training SAMPLES (there is no mini-batch to average //--- over). <=1 silently disables the layer, which is the only other meaningful setting. const int BatchNormWindow = 1000; // AI: batch-norm window (samples) //--- Training starts at the earliest available bar (floored by MinTrainYear); the honest generalisation //--- read comes from this holdout, not from withholding history. input OOS_SPLIT_PRESET OOSSplit = OOS_30; // Out-of-sample holdout //--- There is no "target accuracy" input: training runs until it stops improving and deploys its //--- own best checkpoint (see the PLATEAU_* ladder). //================================================================================================== // CLASS IMBALANCE - ONE MECHANISM, NO KNOB //================================================================================================== //--- LOGIT-ADJUSTED LOSS (Menon et al. 2021): add tau*log(prior_c) to each class logit inside the //--- TRAINING gradient only, so the raw argmax at inference is already balanced-error-optimal. //--- tau is fixed at 1.0 - the full log-prior, the paper's consistent value; the priors come from the //--- label prebuild's measured distribution, and the delivered strength is capped to the head's //--- usable logit range (see ApplyLogitAdjustment). There is nothing left for a user to choose. //--- Freeze the measured class priors after the first measurement. Letting them track is correct since //--- the barrier relabel; freezing is a diagnostic for a genuinely shifting distribution. const bool FreezePriorCalibration = false; //--- Repainting embargo for the swing-context FEATURES (not the labels - their lookahead control is //--- the pivot-pair finality rule). ZigZag revises its recent legs, so a raw read would be straight //--- lookahead. const SWING_CONFIRMATION_PRESET SwingConfirmationBars = SC_100; //--- Keep adapting a deployed model on a LIVE chart to newly-RESOLVED bars. The blend FREEZES if a //--- rolling-accuracy guardrail decays, so drift cannot reach the account. No effect in the tester. const bool EnableOnlineLearning = true; //--- SIGNAL COOLDOWN. NOT display-only - the previous comment here said so and was WRONG: when this //--- suppresses a bar, CExpertSignalAIBase's live path zeroes the signal outright, so there is no //--- arrow, no vote and NO POSITION. It gates trading, the tester and the drawn history alike. What it //--- does NOT touch is training: labels, features and backprop never see it, so changing these costs //--- no retrain and they are deliberately absent from the fingerprint. //--- //--- INPUTS, not constants, because the right value is per-chart and per-timeframe and could not be //--- tuned without a recompile before. The raw per-bar metrics are still never declustered. input string CD_Settings = "Signal Cooldown"; // Signal Cooldown input SIGNAL_COOLDOWN_SCOPE Signal_CooldownScope = SIGNAL_COOLDOWN_ANY_SIGNAL; // Cooldown: what a signal blocks //--- Bars between signals. 0 disables the cooldown entirely. //--- DEFAULT 30, and the floor is PRINCIPLED rather than cosmetic: a trade on this label is held for //--- 5 + the median ZigZag leg = 18-19 bars, so any second signal inside that window is the SAME //--- trade being re-announced. 20 is therefore the smallest defensible value; 30 is one comfortable //--- step above it, and was chosen because the measured natural spacing between vote arrows is ~20 //--- bars - a window at or below that thins almost nothing (10 bars removed only 8-21%). input SIGNAL_COOLDOWN_BARS Signal_CooldownBars = SCB_30; // Cooldown: bars between signals //--- OVERRIDES the bar count when > 0, so a cooldown can be expressed in wall-clock and stay put //--- across a timeframe change. Converted to bars against the CHART's period, so it is exact on //--- every timeframe rather than approximated. input SIGNAL_COOLDOWN_MINUTES Signal_CooldownMinutes = SCM_OFF; // Cooldown: minutes instead //--- ONE resolver, so the member layer and the VOTE layer can never disagree about the window. The //--- minutes form overrides the bar count and is resolved against the CHART period, rounded UP so a //--- cooldown asked for in wall-clock is never silently shorter than requested. //--- SOURCE OVERRIDE, and it exists because of a trap this codebase already documents: MT5 stores an //--- input PER CHART in profiles\Charts\*\chart*.chr, so AN ALREADY-ATTACHED EA IGNORES A CHANGED //--- DEFAULT ENTIRELY. Raising Signal_CooldownBars from 10 to 30 changed nothing on six live charts - //--- they kept reporting a 10-bar window - because each had 10 saved in its own profile. //--- //--- That is precisely why SignalClusterWindow was a const before this work. Making it an input //--- restored per-chart tunability and lost source-correctability; this restores the second without //--- giving up the first. //--- //--- > 0 WINS over the input. 0 hands control back to the panel. Set it to 0 once the charts have //--- been re-attached or their inputs set by hand. const int SignalCooldownOverrideBars = 30; int WarriorSignalCooldownBars(void) { int bars = (int)Signal_CooldownBars; //--- MINUTES FIRST, so the source override below is genuinely LAST and wins over both. Applying it //--- before this block left a latent copy of the very bug it exists to fix: Signal_CooldownMinutes //--- is a per-chart input too, so a chart carrying a stored minutes value would have silently //--- defeated the override. Harmless while every chart holds SCM_OFF, which is exactly the kind of //--- "works today" that stops working the first time someone sets it. if(Signal_CooldownMinutes > 0) { int secs = PeriodSeconds(); if(secs > 0) bars = (int)MathCeil(((int)Signal_CooldownMinutes * 60.0) / secs); } //--- LAST WORD. Deliberately NOT applied when the resolved value is OFF: an operator who switched //--- the cooldown off meant it, and silently re-enabling it from source would be the same class of //--- surprise this override exists to fix, pointed the other way. if(SignalCooldownOverrideBars > 0 && bars > 0) bars = SignalCooldownOverrideBars; return (bars > 0) ? bars : 0; } //--- ONE PASS OVER THE HELD-OUT SLICE, at deploy, after the best checkpoint is restored. //--- //--- WHAT IT BUYS: the OOS slice is the NEWEST history and the model never trains on it, while online //--- learning adapts to every bar that resolves AFTER deployment. That leaves a gap exactly at the //--- handover, over the most regime-relevant data there is. This is the standard //--- select-on-validation-then-refit-on-everything move. //--- //--- WHAT IT COSTS, and it is not nothing: the deployed weights are then NOT the weights that were //--- measured. The deploy log's promise - "every model reverts to the weights it held at the era //--- whose combined vote scored best, so the ensemble that trades is exactly the one that was //--- measured" - stops being literally true. Every certified number belongs to the PRE-PASS weights //--- and must be quoted that way. //--- //--- Set false to keep certified == traded exactly. const bool EnableOosFinalPass = true; //--- A second small net predicting how FAR price travels within the horizon - never which way. Stage 1 //--- is a MEASUREMENT: it prints a Brier skill score and places no orders. Not in the fingerprint. const bool UseExcursionHead = true; //--- Runaway backstop, not a training control - the plateau ladder decides when a run ends. const MAX_ERAS_PRESET MaxErasPerRun = ME_10000; //================================================================================================== // AI INPUT FEATURES (the data the neural network sees each bar) //================================================================================================== input string AISignals = "AI Input Features"; // AI Input Features //--- Bars per input sequence is DERIVED (DeriveHistoryBars) and pinned in the .cfg. The ATR feature //--- period is deliberately decoupled and fixed: the indicator is created before the .cfg is adopted, //--- so deriving it would let init ordering change the unit the pinned SL/TP multiples are expressed in. #define ATR_FEATURE_PERIOD 20 input ENUM_APPLIED_VOLUME VolumeData = VOLUME_TICK; // Volume data type (tick / real) input bool EnableVolume = true; // Feature: volume input bool EnableTime = true; // Feature: time input bool EnableATR = true; // Feature: volatility (ATR) input bool EnableMAFeature = true; // Feature: Moving Average //--- Widths are per BAR, so each is multiplied by the sequence length - enable deliberately. input bool EnableSwingContext = true; // Feature: ZigZag swing context //--- THE RSI, MACD, ICHIMOKU AND FIVE AD/WYCKOFF FEATURE GROUPS WERE REMOVED 2026-08-24. Every one //--- had shipped false, and each carried a closed verdict: the classic oscillators are the same 26 //--- patterns that measured at chance as entries, and the Wyckoff family returned zero out-of-sample //--- on five independent instruments, which is what closed the context score. Their widths were //--- already 0 in the input matrix, so removing them changes no fingerprint and orphans no model. //================================================================================================== // AD / WYCKOFF INDICATOR PARAMETERS //================================================================================================== //--- Tuner seeds, one per CONCEPT rather than per indicator (volClimax/volHigh/rangeClimax/... were //--- restated verbatim across four indicators). The auto-tuner is the operator path to these values; //--- editing a _DEF is a deliberate speed bump, because hand-set values bypass its family-wise gate. #define WYK_VOL_CLIMAX_DEF 2.5 #define WYK_VOL_HIGH_DEF 1.5 #define WYK_RANGE_CLIMAX_DEF 1.8 #define WYK_RANGE_SIGNIF_DEF 1.2 #define WYK_ST_VOL_RATIO_DEF 0.6 #define WYK_ATR_MULT_DEF 0.5 #define ADCD_LOOKBACK_DEF 50 #define SOT_THRUST_LOOKBACK_DEF 30 #define SOT_MIN_IMPULSES_DEF 3 #define SOT_THRESHOLD_DEF 0.30 #define WES_LOOKBACK_DEF 50 #define WES_ZIGZAG_DEF 3 #define WES_TOUCH_ATR_DEF 0.5 #define WES_AR_MIN_ATR_DEF 1.0 #define WES_MAX_RANGE_BARS_DEF 200 #define WFS_LOOKBACK_DEF 50 #define WFS_ZIGZAG_STRENGTH_DEF 3 #define WSBI_LOOKBACK_DEF 50 //--- Aliases keeping every consumer (CADIndicatorTuner seeds, ConfigFingerprint's ADP token) untouched. #define Wyk_VolClimaxMult WYK_VOL_CLIMAX_DEF #define Wyk_VolHighMult WYK_VOL_HIGH_DEF #define Wyk_RangeClimaxMult WYK_RANGE_CLIMAX_DEF #define Wyk_RangeSignificantMult WYK_RANGE_SIGNIF_DEF #define Wyk_ShortTermVolRatio WYK_ST_VOL_RATIO_DEF #define Wyk_AtrMult WYK_ATR_MULT_DEF #define ADCD_Lookback ADCD_LOOKBACK_DEF #define SOT_ThrustLookback SOT_THRUST_LOOKBACK_DEF #define SOT_MinImpulses SOT_MIN_IMPULSES_DEF #define SOT_Threshold SOT_THRESHOLD_DEF #define WES_Lookback WES_LOOKBACK_DEF #define WES_ZigZag WES_ZIGZAG_DEF #define WES_TouchATR WES_TOUCH_ATR_DEF #define WES_ARMinATR WES_AR_MIN_ATR_DEF #define WES_MaxRangeBars WES_MAX_RANGE_BARS_DEF #define WFS_Lookback WFS_LOOKBACK_DEF #define WFS_ZigZagStrength WFS_ZIGZAG_STRENGTH_DEF #define WSBI_Lookback WSBI_LOOKBACK_DEF //--- Proximity/impact only, never actual-vs-forecast, which is not knowable ahead of the release. input bool EnableNews = false; // Feature: news proximity input NF_LOOKBACK_PRESETS NewsFeatureWindowMinutes = M60; // News feature window //--- Currency-strength panel built from the FX pairs in Market Watch. Needs >= 2 usable pairs; degrades //--- to a neutral 0-fill with one logged line rather than blocking training. input bool EnableCrossAsset = true; // Feature: cross-asset currency strength //--- The only microstructure channel that is both FX-available and genuinely historical in the tester. //--- Encodes a volatility REGIME; unsigned, like volume, so it can never pick a side. input bool EnableSpreadFeature = true; // Feature: spread / volatility regime //--- Gates CONSUMPTION only. With no file for this symbol the block contributes 0 features and the //--- topology is unchanged, so it is safe ON everywhere. Turning it OFF on a model trained WITH alt //--- features shrinks the input width and correctly starts a fresh model. input bool EnableAltData = true; // Feature: alternative data (COT / VIX / macro) //--- Keys travel as input defaults so wiping Common\Files\Warrior_EA cannot silently kill a source. //--- A keys.txt in the AltData folder is consulted only if an input is blanked. COT needs no key. input string FredApiKey = "9640c07ff6574c1c23a17393b735fd36"; // FRED API key (VIX/USD features) input string EiaApiKey = "oeSZu7EaZxG5Icjm6q78yUIXaH2EKGhIwVsdTj76"; // EIA API key (petroleum features) //--- Searches the per-bar parameters of every ENABLED feature under a family-wise gate; the trial //--- budget is derived, not configured (ComputeTuneTrialBudget). input bool AutoTuneIndicators = true; // Auto-tune indicator params (gated, era 0) //================================================================================================== // FILTERS //================================================================================================== input string SF_Settings = "Session Filter"; // Session Filter input bool EnableSessionFilter = false; // Signal: Session filter //--- All three ON spans 00:00-22:00 GMT. The filter is evaluated once per BAR, so on D1 there is exactly //--- one evaluation and a narrow default can starve the EA of entries entirely. input bool SF_trade_LondonSession = true; // Trade London session input bool SF_trade_TokyoSession = true; // Trade Tokyo session input bool SF_trade_NewYorkSession = true; // Trade New York session //--- Its own group because CExpertCustom::OnTick() evaluates this schedule unconditionally - it fires //--- whether EnableSessionFilter is on or off. Set Close-all day = Disabled to switch it off. input string CA_Settings = "Scheduled Close-All"; // Scheduled Close-All input CLOSE_DAY_OF_WEEK targetDayOfWeek = CLOSE_FRIDAY; // Close-all day //--- CH_MARKET_CLOSE resolves per day from the symbol's own session table and backs off by the //--- minute setting, so it is right on every symbol and both sides of DST with no number to //--- maintain. input CLOSE_HOUR_OF_DAY targetHour = CH_MARKET_CLOSE; // Close-all hour input CLOSE_MINUTE_OF_HOUR targetMinutes = CM_5; // Close-all minute input string NF_Settings = "News Filter"; // News Filter input bool EnableNewsFilter = true; // Signal: News filter input NF_LOOKBACK_PRESETS NF_LookMinutes = M60; // News avoid window (min) input NF_IMPACT_PRESETS NF_MinImpact = HOLIDAYS; // Min news impact to avoid input string RiskGuard_Settings = "Risk Guard"; // Risk Guard input bool EnableRiskGuard = true; // Signal: Risk Guard //--- Free entry rather than a preset ladder, because prop limits are not always integers. Enter the //--- limits from YOUR account agreement, slightly tighter if you want margin for slippage past a stop. //--- 0 disables a rule. Enforced at quote frequency by Variables\RiskBudget.mqh, not once per bar. input double MaxDailyLossPct = 4.0; // Daily loss limit % (0 = off) input double MaxDrawdownPct = 8.0; // Max total drawdown % (0 = off) //--- TRUE: measured down from the highest equity ever reached. FALSE: from the equity first seen. Use //--- whichever your programme uses - a trailing rule on a static challenge halts far too early. input bool MaxDrawdownIsTrailing = true; // Max DD trails the equity peak //--- Broker-server hour, NOT local time. A misaligned window hands the allowance back early or late. input int RiskDayResetHour = 0; // Risk day reset hour (broker time, 0-23) //--- Share of the allowance genuinely LEFT after every open position's remaining loss-to-stop. Without //--- it a trade at 3.2% into a 4% day still sized for a full risk unit and a routine stop-out breached. input double RiskPerTradeOfBudget = 50.0; // Max % of remaining budget per trade //--- Declining new entries cannot stop an ALREADY-OPEN position running through the limit, which is how //--- a hard daily rule is actually breached. OFF means the limits above are advisory, not enforced. input bool RiskGuardFlatten = false; // Close own positions on breach //--- EXPECTANCY STOP. The limits above bound how FAST the account loses, never WHETHER. 0 = off. //--- The halt is LATCHED and survives a restart; clearing it means deleting the risk state file. input int ExpectancyMinTrades = 40; // Halt if losing: min closed trades first (0 = off) input double ExpectancySigma = 2.0; // ...and mean must be this many std errors below zero //================================================================================================== // TRADE JOURNAL / PATTERN RANKING //================================================================================================== input string Journal_Settings = "Trade Journal / Ranking"; // Trade Journal / Ranking //--- Scales each signal's vote by its historical win rate, records every trade, and powers the Export //--- Trade Journal Report button. input bool UseDatabaseRanking = true; // Weight filters by DB win-rate //--- Oldest row pruned past the cap. A high cap costs nothing until the rows exist. input int DB_MaxRowsPerTable = 1000000; // Max rows kept per pattern table //--- Header only - AI\Network.mqh's Adam*/Sgd* inputs render immediately after this divider. input string NNPerf_Settings = "NN Optimizer / Performance"; // NN Optimizer / Performance //--- Guarded, so the explicit include in Warrior_EA.mq5 stays harmless: every unit that sees the seed //--- constants above also sees the g_Tuned* globals that supersede them. #include "TunedPeriods.mqh" //================================================================================================== // THE TWO BOOKS - MAGIC NUMBERS //================================================================================================== //--- Allow_Hedging gives this EA a second position slot on the same symbol, and a position is //--- addressed by (symbol, magic) everywhere in MT5 - so the short book needs a magic of its own. //--- The LONG book keeps Expert_MagicNumber unchanged: every position, journal row and risk-budget //--- state file this EA has ever written stays addressable exactly as before, and turning hedging on //--- adopts no existing position into the wrong book. //--- //--- The offset is +1, so magic N and N+1 are BOTH reserved by this EA. Every filter that uses them //--- also matches the symbol, so the six charts sharing magic 2024 stay disjoint - but do not point a //--- second EA at Expert_MagicNumber+1. #define SHORT_BOOK_MAGIC_OFFSET 1 //--- The vote exit is pinned shut here rather than left at the stock CExpertSignal default of 100: //--- the vote is a WEIGHTED MEAN of values that cannot exceed 100, so it CAN reach 100 exactly, and //--- 100 would therefore arm an exit this strategy is not certified for. 101 is unreachable by //--- arithmetic. See Signal_ThresholdClose's removal note above. #define VOTE_EXIT_DISABLED_THRESHOLD 101 //--- Band the assigned magics live in. Deliberately far from the values people type by hand (2024, //--- 12345, 999) so an auto-assigned magic never collides with a hand-set one on the same account. #define WARRIOR_MAGIC_BAND 1400000000 #define WARRIOR_MAGIC_SLOTS 100000 //--- Resolved once per run. 0 = not resolved yet; WarriorBookMagic() is called from per-tick filters, //--- so the file must be touched exactly once and never again. ulong g_warriorBaseMagic = 0; //--- DETERMINISTIC FALLBACK, from chart identity. Used in the tester (where a random magic would make //--- two identical passes differ) and whenever the file cannot be written - a magic that is stable //--- WITHOUT a file is a far better failure mode than one that is fresh on every start. ulong WarriorDerivedMagicBase(void) { string key = _Symbol + "|" + IntegerToString((int)_Period); uint h = 2166136261; int n = StringLen(key); for(int i = 0; i < n; i++) { h ^= (uint)StringGetCharacter(key, i); h *= 16777619; } //--- EVEN SLOTS ONLY. The short book is base+1, so odd bases would let one chart's short book land //--- exactly on another chart's long book. return (WARRIOR_MAGIC_BAND + 2 * (ulong)(h % WARRIOR_MAGIC_SLOTS)); } string WarriorMagicFileName(void) { return StringFormat("Warrior_%s_%d.magic", _Symbol, (int)_Period); } //--- ASSIGN-ONCE-AND-REMEMBER. Terminal-local (MQL5\Files) ON PURPOSE, not Common: the Common //--- Warrior_EA folder is the one that gets wiped for a retrain, and positions outlive retrains. It //--- also keeps two terminals running the same symbol on separate magics, which a chart-identity hash //--- could not do. ulong WarriorResolveBaseMagic(void) { if(g_warriorBaseMagic != 0) return g_warriorBaseMagic; //--- Reproducibility beats uniqueness in the tester: two identical passes must not differ. if(MQLInfoInteger(MQL_TESTER) || MQLInfoInteger(MQL_OPTIMIZATION) || MQLInfoInteger(MQL_FORWARD)) { g_warriorBaseMagic = WarriorDerivedMagicBase(); return g_warriorBaseMagic; } string file = WarriorMagicFileName(); //--- SHARE flags on every open, always - see the tester optcache corruption this project already ate. int h = FileOpen(file, FILE_READ | FILE_TXT | FILE_ANSI | FILE_SHARE_READ | FILE_SHARE_WRITE); if(h != INVALID_HANDLE) { string line = FileReadString(h); FileClose(h); ulong stored = (ulong)StringToInteger(line); if(stored != 0) { g_warriorBaseMagic = stored; PrintFormat("Warrior magic: reusing %I64u for %s (from %s) - the positions this EA already" " holds stay recognisable across this restart.", stored, _Symbol, file); return g_warriorBaseMagic; } PrintFormat("Warrior magic: %s exists but holds no usable value (\"%s\") - assigning a new one.", file, line); } //--- No usable file. Draw one, then PERSIST IT BEFORE RETURNING - a magic that was never written //--- down is exactly the orphaned-positions failure this whole mechanism exists to prevent. MathSrand((int)(GetTickCount() + (uint)TimeLocal() + (uint)StringLen(_Symbol) * 7919)); //--- MathRand() is 0..32767, so one draw cannot cover the slot range. Two do. uint draw = ((uint)MathRand() << 15) ^ (uint)MathRand(); ulong candidate = WARRIOR_MAGIC_BAND + 2 * (ulong)(draw % WARRIOR_MAGIC_SLOTS); int w = FileOpen(file, FILE_WRITE | FILE_TXT | FILE_ANSI | FILE_SHARE_READ | FILE_SHARE_WRITE); if(w == INVALID_HANDLE) { g_warriorBaseMagic = WarriorDerivedMagicBase(); PrintFormat("Warrior magic: CANNOT WRITE %s (error %d) - falling back to the chart-derived magic" " %I64u, which is stable without a file. Trading continues; the assigned-random path" " is what is unavailable, not position tracking.", file, GetLastError(), g_warriorBaseMagic); return g_warriorBaseMagic; } FileWriteString(w, IntegerToString((long)candidate)); FileClose(w); g_warriorBaseMagic = candidate; PrintFormat("Warrior magic: assigned %I64u to %s and wrote it to %s. Every later start reads it" " back, so positions opened under it stay managed.", candidate, _Symbol, file); return g_warriorBaseMagic; } ulong WarriorBookMagic(const bool longBook) { //--- An explicitly pinned value wins and never touches the file: a chart already carrying 2024 //--- keeps addressing the positions it opened under 2024. ulong base = (Expert_MagicNumber != 0) ? Expert_MagicNumber : WarriorResolveBaseMagic(); return (longBook ? base : base + SHORT_BOOK_MAGIC_OFFSET); } //--- IS THIS POSITION/ORDER OURS? Used by every sweep that acts on the EA's own trades - the //--- scheduled close-all, the risk budget's emergency flatten, the journal's MAE/MFE walk. //--- //--- DELIBERATELY NOT GATED ON Allow_Hedging. Ownership must not depend on a switch: turn hedging //--- off while a short-book position is open and a gated predicate would stop recognising it, so the //--- close-all would skip it and the flatten would leave it running - a position no code would ever //--- close again. Only OPENING a short book is gated by the input; owning one is forever. This is the //--- same asymmetry as ProtectOpenPosition(): an exit may act where an entry may not. //--- THE LEGACY PAIR. 2024 was this EA's shipped default magic for its whole life, so positions opened //--- under it must stay recognisable even after a chart is switched to the assign-and-remember scheme //--- (Expert_MagicNumber = 0). Without this, flipping a chart while a position was open would orphan //--- it - still running, invisible to the close-all and the flatten, managed by nothing. Every filter //--- that calls this ALSO matches the symbol, so claiming these two values can only ever reach //--- positions on this EA's own chart. Safe to delete once no 2024-era position can still be open. #define WARRIOR_LEGACY_MAGIC 2024 bool WarriorOwnsMagic(const long magic) { if(magic == (long)WarriorBookMagic(true) || magic == (long)WarriorBookMagic(false)) return true; return (magic == WARRIOR_LEGACY_MAGIC || magic == WARRIOR_LEGACY_MAGIC + SHORT_BOOK_MAGIC_OFFSET); } //--- Is the two-book mode actually live? Needs BOTH the input and an account that can hold opposing //--- positions - on NETTING the second book is arithmetically impossible, so the EA runs its original //--- single-position path and says so once at init. bool WarriorHedgingActive(void) { return (Allow_Hedging && (ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE) == ACCOUNT_MARGIN_MODE_RETAIL_HEDGING); }