forked from animatedread/Warrior_EA
The daily (4%) and total (8%) rules bound how FAST an account can lose. Nothing
noticed WHETHER it was losing. A negative-expectancy signal traded at 1% inside
that envelope breaches no rule and still arrives at zero - it just takes longer,
with every limit green the whole way down. That is the realistic way this EA
destroys an account, and no existing guard could see it.
THE ARITHMETIC THIS ENFORCES. Expected value per trade is p*TP - (1-p)*SL - cost.
With no directional edge p equals SL/(SL+TP), which is also the break-even rate,
so the payoff terms cancel exactly and EV = -cost. Expected P&L is -(trades) x
cost: strictly negative, proportional to activity. Measured here: directional
precision 23-24% against a 25% break-even, flat across every confidence tier,
with 58 points of spread on SP500. Sizing, stop placement and trailing move
variance around that mean; none of them changes its sign.
So every closed position now reports its result in R (net profit over money
actually at risk) and the running mean is tested against zero. Above the
configured minimum sample, if mean + sigma*SE < 0, new entries stop.
- SIGNIFICANTLY below, not merely below. A run of losers is ordinary variance
even for a profitable system; halting on the raw mean would be the same
act-on-noise error the MI gates exist to prevent. Using the standard error
means a wide spread simply demands more trades before the rule can fire.
- NET of swap and commission (ResolveClose already sums all three). Deliberate
and load-bearing: when the edge is zero, cost IS the expectancy, so a gross
version would measure a strategy nobody can trade.
- Reported in R so symbols, lot sizes and balances share one scale and one
mean. Trades without a stop are not scored rather than assigned a guessed R.
- LATCHED across restarts, like the daily halt and for the same reason: a
latch a reattach clears is not a latch. Clearing it means deleting the risk
state file, deliberately, after looking at why.
State is appended to the risk file length-guarded, so files written before this
still load and start their sample at zero rather than misreading.
Defaults 40 trades / 2 sigma; ExpectancyMinTrades = 0 disables it.
This does not make the strategy profitable and is not meant to. It stops paying
tuition on one the results say is losing, and does it on measurement rather than
on a drawdown limit finally being reached.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
546 lines
48 KiB
MQL5
546 lines
48 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| Inputs.mqh |
|
|
//| AnimateDread |
|
|
//| https://www.mql5.com |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "AnimateDread"
|
|
#property link "https://www.mql5.com"
|
|
#include "..\Enumerations\InputEnums.mqh"
|
|
//--- Each `input string *_Settings` below is a GUI-only section divider: MetaTrader renders an input
|
|
//--- string whose value equals its comment as a header. Never read by MQL5 code - that's expected, not
|
|
//--- dead wiring. Sections are ordered most-used first: General, Money, Trade, Classic Signals,
|
|
//--- Neural Network, AI Input Features, Filters, Trade Journal - then NN Optimizer / Performance LAST.
|
|
//--- The Neural Network block sits directly ABOVE AI Input Features because that is the reading order a
|
|
//--- user actually needs: choose the architecture, then choose what it sees. NN Optimizer / Performance
|
|
//--- must remain the final divider in this file - the Adam/Sgd inputs are declared in AI\Network.mqh and
|
|
//--- render immediately after it, so anything added below would land inside that group.
|
|
//==================================================================================================
|
|
// GENERAL
|
|
//==================================================================================================
|
|
input string Expert_Settings = "General"; // General
|
|
input ulong Expert_MagicNumber = 2024; // Magic number (unique EA id)
|
|
input bool Expert_EveryTick = false; // Calculate on every tick
|
|
//--- NO LONGER AN INPUT (2026-08-01). The detailed panel/journal is a developer view: a buyer does not
|
|
//--- care which plateau stage the ladder is on, and every row in the Inputs tab is a row they have to
|
|
//--- read past to reach something that matters. Same reasoning that already applied to DebuggingMode
|
|
//--- below, so the two now sit together. Flip to true and recompile to work on the EA.
|
|
const bool VerboseMode = false;
|
|
//--- DELIBERATELY NOT AN INPUT. Development diagnostics: dumps the training internals that used to sit on
|
|
//--- the on-chart panel (plateau-ladder stage, eras-since-best, the deploy gate, selection internals) into
|
|
//--- the Experts journal instead, where they cost the user nothing. This is a commercial product - the
|
|
//--- default panel has to read like a product, not like a training console, so anything a buyer cannot act
|
|
//--- on belongs in a log. Flip to true and recompile when diagnosing a training run.
|
|
const bool DebuggingMode = false;
|
|
//--- ALSO NOT AN INPUT, and for a stronger reason than DebuggingMode. Pins the dense-taper depth instead
|
|
//--- of deriving it (ComputeHiddenLayerCount), purely so a depth comparison can still be run while
|
|
//--- working on the EA. 0 = derived, which is the only value that should ever ship. A user who picks a
|
|
//--- depth is contradicting the first-layer width and the taper the code derived around it - that
|
|
//--- contradiction is exactly what the MLP_3L/MLP_4L presets used to allow.
|
|
//--- NOTE the limitation: this is compile-time, and it feeds the weights-filename fingerprint only when
|
|
//--- non-zero, so two forced depths get their own model files but cannot run SIMULTANEOUSLY from one
|
|
//--- .ex5. Depth comparisons are sequential unless you deploy two separately-compiled builds.
|
|
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
|
|
input TRADING_DIRECTION tradingdirection = BOTH; // Trade direction
|
|
//--- ENTRY / STOP / TARGET ARE NO LONGER INPUTS (2026-08-07). They were three enums the user had to pick,
|
|
//--- and in the tester they were three more axes for a genetic optimization to overfit. The barrier
|
|
//--- geometry is now MEASURED (ReportBarrierGeometryScan picks the SL:TP pairing that carries the most
|
|
//--- entry-time information about its own outcome, and only adopts it when it clears a family-wise
|
|
//--- significance gate - otherwise these defaults stand). Kept as named constants rather than deleted so
|
|
//--- every existing reference still reads the same, and so the fallback is stated in one place.
|
|
//---
|
|
//--- Entry is pinned to MARKET deliberately. The pending-order modes place the entry at a LEVEL while the
|
|
//--- rest of the pipeline measures from the bar open, which is precisely the mismatch that manufactured
|
|
//--- the +0.097 R "retail fade" result later retracted as a fill artifact - a pending entry cannot be
|
|
//--- honestly simulated by this codebase's own fill model, so it is not offered.
|
|
const ENTRY_MULTIPLIER Entry_Multiplier = MARKET; // Entry type/offset (fixed - see above)
|
|
//--- SL 1*ATR below/above the ENTRY, TP 3*ATR from it. These three ship as a consistent SET: risk is
|
|
//--- exactly 1*ATR and reward exactly 3*ATR, so the realised reward:risk is 3.0 and clears the 1:2
|
|
//--- rejection filter with margin. TP_ATR_x2 would sit EXACTLY on the 2.0 boundary, where price
|
|
//--- normalization rounding alone can push `reward` a tick under `minRR*risk` and reject the setup -
|
|
//--- so the default deliberately leaves a gap. If you raise Min_Risk_Reward_Ratio above 3, raise TP
|
|
//--- with it or nothing will ever fire (see TP_INTELLIGENT_BASE_RR in Expert\ExpertSignalCustom.mqh
|
|
//--- for the incident where exactly that combination rejected 100% of setups on every symbol).
|
|
//--- STARTING geometry only. The scan may replace this pair at era 0 on a fresh model; a model that has
|
|
//--- already been trained reads its pinned pair back out of the .cfg and never re-measures, so the labels
|
|
//--- a run started with are the labels it finishes with.
|
|
const STOP_LOSS_MODE SL_Mode = SL_ATR_x2; // Stop-loss mode (measured - see above)
|
|
const TAKE_PROFIT_MODE TP_Mode = TP_ATR_x6; // Take-profit mode (measured - see above)
|
|
input RISK_REWARD_RATIO Min_Risk_Reward_Ratio = RR_1x2; // Min reward:risk (reject only)
|
|
input TRAILING_STRATEGY TrailingStrategy = TRAILING_STRATEGY_NONE; // Trailing stop
|
|
input BARS_EXPIRATION Signal_Expiration = BARS_X3; // Pending order expiry (bars)
|
|
input CONFIDENCE_SOURCE Confidence_Source = CONF_AI; // AI confidence source (SL/TP/trail/exit/MM)
|
|
//--- UNIFIED conviction gates - ONE pair of thresholds governing BOTH engines, classic and AI. There
|
|
//--- used to be a second, AI-only pair in the Neural Network section (Min AI confidence / Min AI exit
|
|
//--- confidence) duplicating these: four inputs for what is really two decisions, where a trader could
|
|
//--- set the vote gate and still be silently overruled by the AI floor (or the reverse). Merged here.
|
|
//--- Everything is expressed on the same 0-100 conviction scale: a classic filter contributes its
|
|
//--- pattern weight (10-100), an AI signal contributes its confidence tier (80-100), and
|
|
//--- CExpertSignalCustom::Direction() averages the filters that voted before
|
|
//--- CheckOpenPosition/CheckClosePosition threshold that average.
|
|
//--- Open - aggregate conviction required to ENTER, and NOTHING else. It has exactly one meaning for
|
|
//--- both engines: the averaged vote across the filters that voted must reach it.
|
|
//--- It used to do two further jobs on the AI side - an entry floor on the winning softmax
|
|
//--- probability, and the base the 4 AI confidence tiers were quartiled from - which put one
|
|
//--- number on two incompatible scales. A 3-class argmax winner is arithmetically >= 1/3, so
|
|
//--- as a floor every setting from 0 to 33 gated precisely nothing, while every setting above
|
|
//--- that ALSO silently moved the tier boundaries. Both jobs are gone. The AI now expresses
|
|
//--- confidence the way a classic signal does - as the WEIGHT of the vote it casts, 25/50/75/
|
|
//--- 100 across its four tiers, quartiled from the head's own structural floor (1/3 for the
|
|
//--- 3-class softmax, 0.5 for the regression head - see CExpertSignalAIBase::ConfidenceTier).
|
|
//--- So this input now reads, for the AI voting alone: 25 = trade any directional call,
|
|
//--- 50 = tier 1 and up, 75 = tier 2 and up, 100 = only near-certain calls. A weak AI call is
|
|
//--- no longer blocked inside the AI - it votes weakly and is filtered here, exactly like a
|
|
//--- weight-10 classic confirmation.
|
|
//--- NOTE in a hybrid setup this is an AVERAGE: a tier-3 AI vote of 100 alongside two
|
|
//--- weight-10 classic confirmations averages to 40, not 100. Raising this input while several
|
|
//--- low-weight classic signals are enabled suppresses strong AI calls by dilution - that is
|
|
//--- inherent to averaging, and it is the same arithmetic the classic-only path has always had.
|
|
//--- Close - OPPOSITE conviction required to EXIT. It drives BOTH exit routes, at the same conviction:
|
|
//--- the averaged rule-based vote, and the AI early exit (how strongly the AI must have flipped
|
|
//--- AGAINST an open position before that alone closes it). There is deliberately no separate
|
|
//--- "Early AI exit" switch any more - it was a third input for what these two routes already
|
|
//--- express, and it could be left off while Close was set, silently discarding the exit the
|
|
//--- trader had just asked for. The two routes are NOT redundant with each other and both are
|
|
//--- needed: the AI's normal vote is one-shot (LongCondition/ShortCondition consume the
|
|
//--- m_lastNonNeutralSignal alternation gate when they fire) and is then AVERAGED with every
|
|
//--- other filter, so an AI reversal that gets diluted below Close on the bar it happens is
|
|
//--- consumed and never re-offered, leaving the position open indefinitely. The early-exit
|
|
//--- route reads the AI's LIVE signed confidence every bar, undiluted, and so still fires.
|
|
//--- Set Close = Disabled to switch off vote-driven exits entirely (SL/TP/trailing only) -
|
|
//--- that turns off both routes at once, since 101 is unreachable on either scale. See
|
|
//--- VOTE_CLOSE_PRESETS in Enumerations\InputEnums.mqh.
|
|
//--- Close defaults ABOVE Open deliberately: a position is an existing commitment with real cost to
|
|
//--- abandon, so reversing out of one should demand more conviction than opening it did, and a signal
|
|
//--- hovering either side of the entry gate must not be able to churn a position open and shut. Both
|
|
//--- were once hardcoded to 10/10 - one value for BOTH directions of the decision, pinned at the LOWEST
|
|
//--- weight any pattern can carry - so with MA/RSI Pattern_0 (weight 10) firing on nearly every bar on
|
|
//--- whichever side of the MA price sits, one cross flipped the average from +10 to -10 and closed the
|
|
//--- position on the very next bar. The stock MQL5 wizard makes the same asymmetric choice, 50 to open
|
|
//--- against 100 to close.
|
|
input PERCENTAGE_PRESETS Min_Vote_Open = PCT_20; // Min vote to open - AI + classic
|
|
input VOTE_CLOSE_PRESETS Min_Vote_Close = VOTE_CLOSE_DISABLED; // Min opposite vote to close - AI + classic
|
|
//==================================================================================================
|
|
// CLASSIC SIGNALS (rule-based MA/RSI votes - trade alongside or instead of the neural network)
|
|
//==================================================================================================
|
|
input string Classic_Settings = "Classic Signals"; // Classic Signals
|
|
//--- EnableMA/EnableRSI default depends on the build (see AIType's declaration comment for the full
|
|
//--- rationale): ON for a Market submission build (WARRIOR_MARKET_BUILD defined) so a fresh install
|
|
//--- trades immediately with no AI warm-up, OFF for the private/live build, which runs AI-only by
|
|
//--- default. Either way this is only a compile-time DEFAULT - still a normal input, changeable per-run
|
|
//--- from the Inputs tab without recompiling.
|
|
#ifdef WARRIOR_MARKET_BUILD
|
|
input bool EnableMA = true; // MA classic vote
|
|
#else
|
|
input bool EnableMA = false; // MA classic vote
|
|
#endif
|
|
#ifdef WARRIOR_MARKET_BUILD
|
|
input bool EnableRSI = true; // RSI classic vote
|
|
#else
|
|
input bool EnableRSI = false; // RSI classic vote
|
|
#endif
|
|
//--- MACD and Ichimoku votes. Unlike EnableMA/EnableRSI above these default OFF in BOTH builds,
|
|
//--- including the Market one: they are additive to a classic set that already trades out of the box
|
|
//--- there, and turning them on by default would silently change the shipped strategy's behaviour rather
|
|
//--- than merely widening the choice. MACD contributes a momentum/divergence model (MA reads level, RSI
|
|
//--- reads a bounded oscillator - neither carries divergence); Ichimoku contributes multi-timescale
|
|
//--- support/resistance structure. Enable per-run from the Inputs tab like any other signal.
|
|
input bool EnableMACD = false; // MACD classic vote
|
|
input bool EnableIchimoku = false; // Ichimoku classic vote
|
|
//--- Indicator parameters below are SHARED: they define the classic votes above AND seed the matching AI
|
|
//--- input features (AI Input Features section) as their starting period, which Auto-tune indicators then
|
|
//--- searches from. Set once here, used by whichever consumer(s) are enabled.
|
|
input MA_PERIOD_PRESETS PeriodMA = MA_PERIOD_50; // MA period
|
|
input MA_TYPE_PRESETS MA_Type = MA_TYPE_SMA; // MA type (SMA/EMA/.../T3/Kalman)
|
|
input RSI_PERIOD_PRESETS PeriodRSI = RSI_PERIOD_14; // RSI period
|
|
//--- MACD AND ICHIMOKU PERIODS ARE NO LONGER INPUTS (2026-08-01). Six dropdowns, pinned here at the
|
|
//--- textbook values every reference uses (12/26/9 and 9/26/52), for three reasons:
|
|
//--- 1. They were six of the largest contributors to the Inputs tab, for indicators that both ship
|
|
//--- DISABLED. Rows a user must scroll past to reach the AI settings are a real cost.
|
|
//--- 2. As optimizer inputs they are an overfitting surface. A genetic sweep across 6 period
|
|
//--- dimensions on one symbol's history will always find a combination that looks excellent and
|
|
//--- generalizes to nothing - and it costs nothing to discover, which is what makes it dangerous.
|
|
//--- 3. They are the SEED for the AI's own auto-tuner (AutoTuneIndicators), which searches from these
|
|
//--- values against a held-out objective. That search is the supported way to move them: it is
|
|
//--- validated, it is per-model, and it cannot silently overfit the way a raw optimizer pass can.
|
|
//--- Left as named constants rather than deleted because they are still read in both roles (classic
|
|
//--- vote periods AND auto-tune starting points), and because the classic textbook values are the
|
|
//--- correct fixed answer for a vote that exists mainly to satisfy marketplace validation.
|
|
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 Network"; // Neural Network
|
|
//--- AIType default depends on the build, via the same WARRIOR_MARKET_BUILD compile-time flag that
|
|
//--- strips the DLL import block for Market submissions (see Warrior_EA.mq5's top-of-file comment) - not
|
|
//--- an input value itself (that can't be set programmatically), only which default the Inputs tab
|
|
//--- starts on:
|
|
//--- - WARRIOR_MARKET_BUILD defined (Market submission): OFF - a fresh install trades from Classic
|
|
//--- Signals (MA/RSI) out of the box with no AI warm-up, satisfying MQL5's automated check for live
|
|
//--- trade activity within its test window.
|
|
//--- - Not defined (private/live build): MLP - this build runs AI-only from the start, with Classic
|
|
//--- Signals defaulting off too (see EnableMA/EnableRSI), so no per-run manual input changes are
|
|
//--- needed switching between preparing a submission and running the real thing.
|
|
//--- Either way, still a normal input - freely changeable per-run from the Inputs tab.
|
|
#ifdef WARRIOR_MARKET_BUILD
|
|
input AI_CHOICE AIType = AI_NONE; // AI architecture preset (or Disabled)
|
|
#else
|
|
input AI_CHOICE AIType = AI_HYBRID; // AI architecture preset (or Disabled)
|
|
#endif
|
|
//--- SGD or ADAM weight update (honored by PAI/CONV/LSTM/HYBRID). SGD rate/momentum are AI\Network.mqh inputs.
|
|
//--- A third "DFA" option was briefly the default (2026-07-28) and has been removed - it was a
|
|
//--- deterministic index-parity sign flip on the gradient, i.e. permanent gradient ASCENT on half of
|
|
//--- every weight tensor, and its backward pass was structurally incompatible with the OpenCL/DirectML
|
|
//--- neuron model. See ENUM_OPTIMIZATION's comment in AI\Network.mqh.
|
|
input ENUM_OPTIMIZATION TrainingOptimizer = ADAM; // Weight optimizer
|
|
//--- OUTPUT TYPE IS NO LONGER AN INPUT (2026-08-01). The regression head (1 tanh output) was an option
|
|
//--- that never made sense for the question this system asks. Since the triple-barrier relabel the
|
|
//--- target is explicitly an EVENT - "does a trade opened here reach its target before its stop" - and
|
|
//--- the right output for an event is its probability, which is what the 3-class softmax head produces.
|
|
//--- A regression head would have to predict a continuous quantity that the label does not even contain,
|
|
//--- and every downstream consumer already speaks probability: the confidence tiers quartile the softmax
|
|
//--- winner, dir-precision is a win rate over called bars, and the class priors calibrate a distribution.
|
|
//--- The regression path is still IMPLEMENTED throughout (m_outputNeuronsCount == 1 branches, the 0.50
|
|
//--- magnitude cutoff in DoubleToSignal) and is left in place deliberately: it costs nothing dormant and
|
|
//--- removing it would touch every scoring path at once for no gain. It is simply no longer selectable.
|
|
const OUTPUT_NEURONS_COUNT OutputNeuronsCount = OUTPUT_CLASSIFICATION;
|
|
//--- No "first layer neurons" input any more. Its only defensible value depends on two things the user
|
|
//--- cannot see - the input-vector width after feature selection, and how much in-sample data the study
|
|
//--- period yields - so it is derived at topology-build time instead. See
|
|
//--- CExpertSignalAIBase::ComputeFirstLayerWidth(). The old default (500) was ~8 parameters per training
|
|
//--- sample and expanded a 420-wide correlated input rather than compressing it.
|
|
//--- No "LSTM hidden size" or "CONV filter count" inputs either, removed 2026-07-30 for exactly the
|
|
//--- reason above: both defaulted to a fixed constant (32 units, 16 filters) chosen without reference to
|
|
//--- the input they sit on, which is the one thing that decides whether either number is sane.
|
|
//--- The conv layer is a per-bar projection (window = step = one bar's features), so 16 filters
|
|
//--- COMPRESSED a 50-feature configuration but EXPANDED a minimal 4-feature one 4x - adding parameters
|
|
//--- below every learnable layer without adding information. The LSTM block is worse: its weight count
|
|
//--- is 4*H*(H+inputs+1), so 32 units against a 540-wide input is ~73k weights, more than double the
|
|
//--- entire derived dense taper it feeds, and it was the one stage the capacity budget never covered.
|
|
//--- Both are now derived from the per-bar feature count and the same one-weight-per-training-bar budget
|
|
//--- the first layer uses. See ComputeConvFilterCount()/ComputeLstmHiddenSize().
|
|
//--- ConvPoolWindow / ConvPoolStep removed 2026-07-29. The pooling stage they configured reduced
|
|
//--- across FILTER channels rather than across time - a consequence of the conv layer's position-major
|
|
//--- output layout that no window/step pair can correct. See AddConvStage() in Expert\ExpertSignalAIBase.mqh.
|
|
//--- No "min neurons" / "reduction per layer" inputs either. With the first layer's width derived
|
|
//--- (ComputeFirstLayerWidth) the taper has no freedom left: it runs geometrically from that width down
|
|
//--- to a final hidden layer sized off the output count, spread over the layer count the chosen AIType
|
|
//--- implies. Keeping either knob would let the user contradict the derivation - and both were
|
|
//--- calibrated for the old hand-picked 500-wide first layer, where they gave 500->150->45; against the
|
|
//--- derived 64 they degenerate to 64->20->20. See BuildFreshTopology()'s taper block.
|
|
//--- Batch normalization (Ioffe & Szegedy 2015) between every pair of dense layers, including just
|
|
//--- before the classification head. ON by default: without it the only bounded stage in the whole
|
|
//--- forward path was the sigmoid head, and the observed failure mode ordered exactly by depth - the
|
|
//--- shallow perceptron held ~52% balanced accuracy while the deepest topology sat on the 33.3%
|
|
//--- one-class floor. It also decouples WEIGHT_DECAY from the learned function, which is what stops
|
|
//--- the slow monotonic decay of the per-bar logit spread that preceded every collapse.
|
|
//--- Left as an input rather than hardcoded so the effect can be A/B'd without a recompile. It is part
|
|
//--- of the weights-filename fingerprint, so flipping it starts a separate model rather than resuming
|
|
//--- an incompatible one. See AI\NeuronBatchNorm.mqh.
|
|
//--- NOT an input. Batch normalization is required, not optional: measured 2026-07-29 on identical
|
|
//--- MLP_3L topologies it was worth +11.3 points of balanced accuracy (57.0% with, 45.7% without),
|
|
//--- stable across 150+ and 200+ eras, and the no-BN control converged to ~5% IS and OOS accuracy
|
|
//--- with no chart signals at all. A user cannot make a good decision here and can easily make a
|
|
//--- ruinous one, so the choice is not offered. Kept as a named constant rather than deleted: the
|
|
//--- topology builder, the weights fingerprint and the .cfg guard all read it, and a constant keeps
|
|
//--- those paths (and the ability to flip it for a diagnostic rebuild) intact.
|
|
const bool EnableBatchNorm = true; // AI: batch normalization
|
|
//--- EMA window the running mean/variance are estimated over, in TRAINING SAMPLES (bars replayed),
|
|
//--- not eras. Training here is pure online SGD - one update per sample - so there is no mini-batch to
|
|
//--- average over and this stands in for the batch size. Long enough to be a stable estimate of the
|
|
//--- feature distribution, short enough to track a genuine regime change. 1000 is ~3% of a typical
|
|
//--- 36k-bar in-sample window.
|
|
//--- Also not an input, for the same reason plus one more: this is a running-statistics window in
|
|
//--- SAMPLES, and nothing on the Inputs tab tells a trader what a good value is. It only ever had
|
|
//--- two meaningful settings - large enough to be a stable estimate, or <=1 which silently disables
|
|
//--- the layer entirely. The first is the only correct one.
|
|
const int BatchNormWindow = 1000; // AI: batch-norm window (samples)
|
|
//--- No "training years" input either, removed 2026-07-30. There is no case for training on less data
|
|
//--- than the broker actually provides: this is a weak signal at a ~6% directional base rate, every extra
|
|
//--- year is more of the minority class, and the honest generalization read comes from the out-of-sample
|
|
//--- holdout below rather than from withholding history. Training now starts at the earliest available
|
|
//--- bar (floored by MinTrainYear, which exists to exclude a broker's dubious pre-history, not to size
|
|
//--- the run). The topology's capacity budget reads the REAL bar count that yields - see
|
|
//--- CExpertSignalAIBase::EstimatedInSampleBars(), and the note there on why that measurement is taken
|
|
//--- exactly once and then pinned.
|
|
input OOS_SPLIT_PRESET OOSSplit = OOS_30; // Out-of-sample holdout
|
|
//--- There is deliberately NO "target accuracy" input. Training runs until it stops improving and then
|
|
//--- deploys its own best model: after a stretch of eras with no new best it tries to escape the plateau
|
|
//--- (learning-rate warm restart, then focal-gamma anneal), and if neither finds anything better it
|
|
//--- finalises the best checkpoint it found. See the PLATEAU_* ladder in Expert\ExpertSignalAIBase.mqh.
|
|
//--- An absolute target could only ever be wrong in one of two directions: set above what a given
|
|
//--- symbol/timeframe can reach and the run never converges (it burns to the era cap and deploys the same
|
|
//--- checkpoint hours later anyway); set below and it stops a run that was still getting better.
|
|
//--- MinRecall stays, and is NOT a performance target - it is the anti-collapse floor that makes
|
|
//--- auto-deploy safe. Buy, Sell AND Neutral must each be recognised this well on held-back data before a
|
|
//--- checkpoint is eligible to ship, so a model that quietly gives up on one direction can never deploy.
|
|
//--- It is an OOS CLASSIFICATION metric (3-class), NOT a trade win rate: random guessing is ~33%.
|
|
//--- 2026-07-29: 60 -> 40. 60 was never demonstrated reachable on this data. The ONE successful
|
|
//--- auto-deploy in the logs (Hybrid, SP500 H1, 28th 00:50, best balanced 66.0%) ran against a 40%
|
|
//--- floor; every run since has been gated at 60 and none has come close - CONV/LSTM/Hybrid peaked at
|
|
//--- 40/49/41% balanced and then decayed, so stage 3 refused to deploy and reset the ladder ~27 times,
|
|
//--- turning a converged run into a 1000-era one-way trip. A floor above what the configuration can
|
|
//--- reach is exactly the "absolute target set too high" failure the comment above warns about, just
|
|
//--- expressed per-class. Raise it again only after a run actually clears it with headroom.
|
|
//--- 2026-08-01: NO LONGER AN INPUT. This is a safety floor, not a preference, and the one direction a
|
|
//--- user can move it is the harmful one - raising it past what the configuration reaches does not
|
|
//--- produce a better model, it produces NO model (nothing clears the gate, stage 3 refuses to deploy,
|
|
//--- and the run burns to the era cap). That failure was observed repeatedly at 60 and is the exact
|
|
//--- catch-22 this floor was nearly deleted over. 40 is the value the only successful auto-deploy in the
|
|
//--- project's history ran against. It also no longer decides what SHIPS - deployability moved to
|
|
//--- directional precision with a derived coverage floor - so it now only drives the diagnostic recall
|
|
//--- line, which makes exposing it even harder to justify.
|
|
const PERCENTAGE_PRESETS MinRecall = PCT_40;
|
|
//--- There are deliberately NO AI-only confidence inputs here any more. The AI entry floor and the AI
|
|
//--- early-exit threshold are the SAME two numbers the classic votes use - Min vote to open / Min
|
|
//--- opposite vote to close (Trade Management section) - so one pair of inputs governs both engines;
|
|
//--- see their declaration comment for how the 0-100 scale maps onto AI softmax confidence and tiers.
|
|
//==================================================================================================
|
|
// CLASS IMBALANCE - ONE MECHANISM, ONE KNOB
|
|
//==================================================================================================
|
|
//--- The directional base rate here is ~3% Buy / ~3% Sell / ~94% Neutral (a ~31:1 imbalance), so the
|
|
//--- loss needs SOME correction or the optimum is "always predict Neutral". This section used to offer
|
|
//--- NINE inputs for that one job. They were consolidated on 2026-07-31 because, audited against the
|
|
//--- code, five of them did not do what their names said at the shipped defaults:
|
|
//--- AILogitPriorStrength DEAD - Inference.mqh's post-hoc prior early-returns when the adjusted
|
|
//--- loss is on, because the offsets are already trained into the weights.
|
|
//--- OversampleParity DEAD in training - Training.mqh gates the replay loop on
|
|
//--- !useLogitAdjustedLoss (correctly: Buda et al. 2018 on why stacking
|
|
//--- oversampling with an analytic correction double-counts the imbalance).
|
|
//--- EnableMinorityReplay DEAD as replay; it survived ONLY as a focal-gamma damper (x0.125).
|
|
//--- ConstrainReplay DEAD as a cap; it only chose between damper 0.125 and 0.25.
|
|
//--- UseStaticPrior an exact duplicate of FreezePriorCalibration - the two were OR'd
|
|
//--- together in the single place either was read.
|
|
//--- Focal loss was the one real redundancy: it ran at gamma*0.125 alongside the adjusted loss, i.e.
|
|
//--- two corrections on the SAME axis, which is what the codebase's own Buda et al. citation warns
|
|
//--- against. Removed rather than re-tuned - the plateau ladder's escape is its learning-rate warm
|
|
//--- restart, and the gamma anneal it also performed was only ever a monotone step toward zero.
|
|
//---
|
|
//--- WHAT REMAINS is LOGIT-ADJUSTED LOSS (Menon et al. 2021, ICLR, "Long-tail learning via logit
|
|
//--- adjustment"): add tau*log(prior_c) to each class logit inside the TRAINING gradient only. The
|
|
//--- network learns to absorb the offset, so at inference its RAW argmax is already the
|
|
//--- balanced-error-optimal decision - no second correction at read time, by construction. Minimizing
|
|
//--- softmax cross-entropy on adjusted logits is consistent for BALANCED error, which is the metric
|
|
//--- checkpoint selection already ranks on, so the loss and the deploy decision optimize the same
|
|
//--- thing. It is the only one of the six with a consistency guarantee, which is why it is the one kept.
|
|
//---
|
|
//--- tau: 100% = tau 1.0, the paper's default and the only value carrying the guarantee. 0 = OFF, which
|
|
//--- is now the honest way to disable the correction entirely (it replaces the old EnableLogitAdjusted-
|
|
//--- Loss boolean - a separate on/off switch beside a strength dial where 0 already means off is two
|
|
//--- controls for one decision). NOTE the runtime auto-caps tau so the offsets cannot swamp the output
|
|
//--- head's usable logit range; the startup line reports the capped value actually used.
|
|
input LOGIT_PRIOR_STRENGTH_PRESETS LogitAdjustTau = LOGIT_PRIOR_100; // AI: class-imbalance correction (tau, 0=off)
|
|
//--- Stop EMA-updating the measured class priors after the first real measurement. NOT AN INPUT as of
|
|
//--- 2026-08-01: it answers a question a user has no way to evaluate ("should the correction track this
|
|
//--- era's tally or the first one's"), and after the triple-barrier relabel the priors barely move
|
|
//--- between eras anyway - the labels are near-balanced and stable, which is the whole point of the
|
|
//--- relabel. Letting them track is the correct default; freezing exists for a symbol whose class
|
|
//--- distribution genuinely shifts mid-run, which is a developer's diagnostic, not a product setting.
|
|
const bool FreezePriorCalibration = false;
|
|
//--- SWING CONFIRM BARS IS NO LONGER AN INPUT (2026-08-01), but the constant is still load-bearing and
|
|
//--- must not be deleted. It stopped gating the LABELS with the triple-barrier relabel - that lookahead
|
|
//--- is now the barrier horizon, which is measured (ComputeBarrierHorizonBars) rather than configured.
|
|
//--- It still gates the swing-context INPUT FEATURES (EnableSwingContext, on by default, 9 features):
|
|
//--- ZigZag revises its most recent legs, so a feature that read the raw current buffer would be reading
|
|
//--- a value the live bar could not actually have had yet. That is straight lookahead into the feature
|
|
//--- vector, so this embargo stays - it simply has no reason to be user-facing, because the correct
|
|
//--- value is a property of the ZigZag indicator's own recalculation depth, not of anyone's preference.
|
|
//--- Kept in the weights fingerprint at its shipped value, so pinning it re-keys nothing.
|
|
const SWING_CONFIRMATION_PRESET SwingConfirmationBars = SC_100;
|
|
//--- Continual learning: after the model is deployed, keep adapting it on a LIVE chart to newly-RESOLVED
|
|
//--- market structure - the same supervised triple-barrier task it was trained on, waiting the full
|
|
//--- barrier horizon so a bar whose outcome is not yet decided is never learned from. The deployed model
|
|
//--- only moves toward the update while a rolling-accuracy guardrail holds; if accuracy decays the blend
|
|
//--- FREEZES (live keeps trading the last-good shadow while the net recovers), so drift cannot reach the
|
|
//--- account. No effect in the Strategy Tester/optimizer - the model is held fixed there by design.
|
|
//--- ON BY DEFAULT AND NO LONGER AN INPUT (2026-08-01). Adapting to a changing market is not an optional
|
|
//--- extra for a model that will be attached for months, it is the thing that keeps it from going stale,
|
|
//--- and the guardrail above is what makes it safe to leave on. See the caveat in the release checklist:
|
|
//--- this had never been forward-tested on a live feed at the time it was made default.
|
|
const bool EnableOnlineLearning = true;
|
|
//--- Default 6 -> 3 and NO LONGER AN INPUT (2026-08-01). Declustering existed because exact-pivot ZigZag
|
|
//--- labels make a same-direction repeat provably redundant; barrier labels answer every bar
|
|
//--- independently, so consecutive Buy setups inside a trend are real trades and suppressing them throws
|
|
//--- signal away - which argued for 0. It is not 0 because on D1 and above a 6-bar window spans more than
|
|
//--- a trading week, and two arrows a day apart on a weekly-scale move really are one event. 3 keeps the
|
|
//--- immediate-neighbour duplicate off the chart on slow timeframes while leaving genuine consecutive
|
|
//--- setups intact on fast ones. Display/emission only either way - the raw per-bar recall/precision
|
|
//--- metrics are never declustered, so this cannot flatter a model's measured numbers.
|
|
const int SignalClusterWindow = 3;
|
|
//--- Era cap. NOT AN INPUT as of 2026-08-01: it is a runaway backstop, not a training control. Training
|
|
//--- decides its own ending (the plateau ladder deploys the best checkpoint once escalation stops finding
|
|
//--- anything better), so in a healthy run this number is never reached and choosing it changes nothing;
|
|
//--- in an unhealthy one the useful response is to read the era log, not to raise a cap.
|
|
const MAX_ERAS_PRESET MaxErasPerRun = ME_1000;
|
|
//==================================================================================================
|
|
// AI INPUT FEATURES (the data the neural network sees each bar)
|
|
//==================================================================================================
|
|
input string AISignals = "AI Input Features"; // AI Input Features
|
|
//--- ind_Periods is the number of bars per input sequence fed to the network (and the ATR lookback).
|
|
//--- Must stay >= ADZigZag Depth (12) so a full swing leg is visible to the model.
|
|
input IND_PERIODS_PRESETS ind_Periods = PERIOD_20; // Bars to analyse
|
|
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)
|
|
//--- MA/RSI as network input features, independent of the Classic Signals votes above (you can feed MA
|
|
//--- to the model without it voting, or vice versa). Uses PeriodMA/MA_Type/PeriodRSI (Classic Signals)
|
|
//--- as the starting period, then auto-tuned from there when Auto-tune indicators is on.
|
|
input bool EnableMAFeature = true; // Feature: Moving Average
|
|
input bool EnableRSIFeature = false; // Feature: RSI
|
|
//--- MACD adds 3 inputs/bar (main, signal, histogram - all ATR-normalized); Ichimoku adds 8 (distances to
|
|
//--- Tenkan/Kijun/both cloud edges, the TK spread, cloud thickness here and projected, and the Chikou
|
|
//--- displacement). Widths are per BAR, so each is multiplied by Bars to analyse before it reaches the
|
|
//--- first layer - Ichimoku at the default 20 bars is 160 extra inputs on its own. Worth it for the
|
|
//--- multi-timescale structure nothing else in the vector carries, but enable deliberately, not by habit.
|
|
input bool EnableMACDFeature = false; // Feature: MACD
|
|
input bool EnableIchimokuFeature = false; // Feature: Ichimoku
|
|
//--- Confirmed ZigZag swing direction/magnitude/age - lookahead-safe (repainting embargo applied, see
|
|
//--- SWING_CONFIRMATION_BARS in Expert\ExpertSignalAIBase.mqh).
|
|
input bool EnableSwingContext = true; // Feature: ZigZag swing context
|
|
input bool EnableADCumulativeDelta = false; // Feature: Cumulative Delta
|
|
input bool EnableADShorteningOfThrust = true; // Feature: Shortening of Thrust
|
|
input bool EnableADWyckoffEventStream = true; // Feature: Wyckoff Events
|
|
input bool EnableADWyckoffFailedStructure = true; // Feature: Wyckoff Failed Structure
|
|
input bool EnableADWyckoffSignificantBarInversion = true; // Feature: Wyckoff Bar Inversion
|
|
//--- News LAST in this list on purpose: it is the only feature whose data comes from outside the price
|
|
//--- series (the terminal's economic calendar), so it is the one a user is most likely to want to reason
|
|
//--- about separately - and the only one with a companion setting. 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
|
|
//--- Cross-asset, after News for the same reason: its data also comes from outside this symbol's own
|
|
//--- series - in fact it is the ONLY feature here that does so without leaving the price domain. Every
|
|
//--- other block above, News included, is either a transform of this one instrument's OHLCV or a
|
|
//--- timing overlay on it. Measured end to end, that whole family sits at the noise floor
|
|
//--- (research/test_classic.py), which is precisely why this exists. Builds a currency-strength panel
|
|
//--- from the FX pairs in Market Watch and feeds the traded pair's base/quote strength plus the
|
|
//--- divergence between the pair and its own two currencies. Needs >= 2 usable FX pairs in Market
|
|
//--- Watch; degrades to a neutral 0-fill with one logged line if it cannot build, never blocks training.
|
|
input bool EnableCrossAsset = true; // Feature: cross-asset currency strength
|
|
//--- Spread: the only microstructure channel that is both FX-available and genuinely historical in
|
|
//--- the Strategy Tester, so the only one a backtest can honestly validate. Encodes a volatility
|
|
//--- REGIME (spread is near-fixed while ATR is not, so the ratio runs high exactly when realised
|
|
//--- volatility is below its ATR estimate), which predicts whether ATR-scaled barriers get reached.
|
|
//--- Unsigned, like volume - it informs Neutral-vs-directional and can never pick a side.
|
|
input bool EnableSpreadFeature = true; // Feature: spread / volatility regime
|
|
//--- Searches the per-bar parameters of every ENABLED input feature above (the order-flow/Wyckoff
|
|
//--- MA/RSI feature periods) for the combination that trains best - see ADIndicatorTuner.mqh.
|
|
//--- The TRIAL COUNT IS NO LONGER AN INPUT (2026-08-01). It was a number the user had no basis to pick:
|
|
//--- the right budget depends on how many parameters are actually being searched and how wide each
|
|
//--- one's range is, both of which the code knows at runtime and the user does not. Asking for it
|
|
//--- guaranteed either a wasted search (too many trials on two narrow parameters) or a blind one (32
|
|
//--- trials against a space of millions). Now derived - see ComputeTuneTrialBudget().
|
|
input bool AutoTuneIndicators = true; // Auto-tune indicator params
|
|
//==================================================================================================
|
|
// FILTERS
|
|
//==================================================================================================
|
|
input string SF_Settings = "Session Filter"; // Session Filter
|
|
input bool EnableSessionFilter = false; // Signal: Session filter
|
|
//--- All three ON by default. The filter is evaluated once per BAR (Expert_EveryTick=false ships as the
|
|
//--- default), so on a slow timeframe there are very few evaluations per day and a single-session
|
|
//--- default can starve the EA of entries entirely - on D1 there is exactly ONE evaluation, at the bar
|
|
//--- open, and whether that instant falls inside a narrow session window depends purely on the broker's
|
|
//--- server offset. Enabling all three spans 00:00-22:00 GMT so only genuinely dead hours are excluded;
|
|
//--- narrow it deliberately per-chart rather than inheriting it as an accident of the default.
|
|
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
|
|
//--- Scheduled flat-close. Deliberately its OWN group rather than part of the Session Filter above:
|
|
//--- CExpertCustom::OnTick() (Expert\ExpertCustom.mqh) evaluates this schedule unconditionally, so it
|
|
//--- fires whether EnableSessionFilter is on or off - grouping it under the session filter implied a
|
|
//--- coupling that has never existed in the code. 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
|
|
input CLOSE_HOUR_OF_DAY targetHour = CH_23; // Close-all hour
|
|
input CLOSE_MINUTE_OF_HOUR targetMinutes = CM_45; // Close-all minute
|
|
//--- INTRADAY TIME FILTER REMOVED ENTIRELY 2026-08-01 (5 inputs, plus Signals\SignalITF.mqh).
|
|
//--- Two of its five inputs were raw BITMASKS ("hours to avoid" as an integer), which is not a setting a
|
|
//--- trader can reasonably compute - it is an implementation detail exposed as a control, and it shipped
|
|
//--- disabled so essentially nobody ever got it right. More importantly the job is now covered three
|
|
//--- times over by things that learn or are declarative: the Session Filter handles "when may I trade"
|
|
//--- explicitly, the time-of-day/day-of-week features (EnableTime) let the NETWORK discover which hours
|
|
//--- are good on this instrument instead of being told, and the trade journal ranks by time bucket.
|
|
//--- A hand-specified hour mask is the least informed of the four and the hardest to use.
|
|
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
|
|
//--- MARKET DEPTH FILTER REMOVED ENTIRELY 2026-08-01 (5 inputs, plus Signals\SignalMarketDepth.mqh).
|
|
//--- It needs real level-2 DOM data, which this development broker does not provide and which most
|
|
//--- retail MT5 brokers do not provide either - so the module has never been executed against real data
|
|
//--- even once. Shipping four tuning dropdowns for an UNTESTED code path is worse than shipping nothing:
|
|
//--- the only users who could enable it are the ones whose broker supplies a book, and they would be
|
|
//--- the first people ever to run it, in live trading, with no validation behind it. If DOM support is
|
|
//--- wanted later it should return as a feature fed to the network rather than as a rule-based veto with
|
|
//--- its own hand-tuned thresholds - the imbalance is data, and data belongs in the input vector.
|
|
input string RiskGuard_Settings = "Risk Guard"; // Risk Guard
|
|
input bool EnableRiskGuard = true; // Signal: Risk Guard
|
|
//--- FREE-ENTRY PERCENTAGES, replacing the RISK_LIMIT_PCT_PRESET dropdown these two used to be
|
|
//--- (that enum is gone - see Enumerations\InputEnums.mqh). Every funded/prop programme sets its own
|
|
//--- numbers and they are not always integers, so a fixed ladder of presets could not express them;
|
|
//--- 4.5% or 3.75% were simply unreachable. Enter the limits from YOUR account agreement, and enter
|
|
//--- them slightly TIGHTER than the contract if you want margin for slippage past a stop.
|
|
//--- 0 disables a rule. Enforced live at quote frequency by Variables\RiskBudget.mqh - not once per
|
|
//--- bar, which is all the old guard could manage.
|
|
input double MaxDailyLossPct = 4.0; // Daily loss limit % (0 = off)
|
|
input double MaxDrawdownPct = 8.0; // Max total drawdown % (0 = off)
|
|
//--- TRUE: max drawdown is measured down from the highest equity ever reached (trailing DD, the
|
|
//--- stricter and more common funded-account rule). FALSE: measured from the equity this EA first
|
|
//--- saw on the account (static DD). Pick whichever your programme actually uses - a trailing rule
|
|
//--- applied to a static challenge halts trading long before it has to.
|
|
input bool MaxDrawdownIsTrailing = true; // Max DD trails the equity peak
|
|
//--- Broker-server hour at which the firm's trading day (and therefore the daily loss allowance)
|
|
//--- resets. Broker time here is NOT your local time; if the firm quotes the reset in another zone,
|
|
//--- convert it. A misaligned window hands the allowance back hours early or late.
|
|
input int RiskDayResetHour = 0; // Risk day reset hour (broker time, 0-23)
|
|
//--- Ceiling on what ONE trade may risk, as a share of the allowance that is genuinely left after
|
|
//--- subtracting every open position's remaining loss-to-stop. This is the fix for the real breach
|
|
//--- mode: without it a trade at 3.2% into a 4% day still sized for a full risk unit and a routine
|
|
//--- stop-out went through the limit. At the default 50% a full stop-out spends at most half of
|
|
//--- what is left, so even a stop that slips to twice its distance lands inside the limit.
|
|
input double RiskPerTradeOfBudget = 50.0; // Max % of remaining budget per trade
|
|
//--- Blocking new entries cannot stop an ALREADY-OPEN position from running through the limit, which
|
|
//--- is the way a hard daily loss rule is actually breached. Turn this on to close this EA's own
|
|
//--- positions (matching symbol + magic) the moment a limit is hit. Default OFF because closing
|
|
//--- positions is a materially bigger behaviour change than declining to open them - but leaving it
|
|
//--- off means the limits above are advisory, not enforced.
|
|
input bool RiskGuardFlatten = false; // Close own positions on breach
|
|
//--- EXPECTANCY STOP. The daily and total limits bound how FAST the account can lose; neither notices
|
|
//--- WHETHER it is losing. A negative-expectancy signal traded inside a 4%/8% envelope breaches no rule
|
|
//--- and still arrives at zero - it just takes longer. This tests the realised mean result per trade
|
|
//--- against zero and stops opening new positions once it is significantly below.
|
|
//--- Significantly, not merely below: a run of losers is ordinary variance even for a profitable system,
|
|
//--- so the test uses the standard error of the mean and a wide spread simply demands more trades before
|
|
//--- it can fire. Measured in R (net profit over money risked), so symbols and lot sizes share one scale,
|
|
//--- and net of swap and commission - when the directional edge is zero, cost IS the expectancy.
|
|
//--- 0 trades = off. The halt is LATCHED and survives a restart; clearing it means deleting the risk
|
|
//--- state file, deliberately, after looking at why.
|
|
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
|
|
//--- Enables the per-pattern win-rate database: scales each signal's vote by its historical win rate,
|
|
//--- records every trade, and powers the Export Trade Journal Report button (see the control panel).
|
|
input bool UseDatabaseRanking = false; // Weight filters by DB win-rate
|
|
//--- Header only. The AI\Network.mqh optimizer inputs (Adam*, Sgd*) are declared in that library
|
|
//--- header; because this Inputs file is included FIRST (see Warrior_EA.mq5), those
|
|
//--- render immediately AFTER this divider - grouping them here instead of leading the Inputs tab.
|
|
input string NNPerf_Settings = "NN Optimizer / Performance"; // NN Optimizer / Performance
|