The old RescanChartSignals ran the entire per-bar inference loop synchronously,
blocking the button-click handler for a potentially long duration on large lookbacks.
Replaced with StartChartSignalRescan (cheap setup) and AdvanceChartSignalRescan
(time-boxed slices) so the heavy work is drained from PollTraining's timer without
freezing the UI.
Introduce `RescanChartSignals()` method and `SIGNAL_RESCAN_LOOKBACK_BARS` define to allow operators to replace stale historical arrows (e.g., from years-old training runs) with fresh inferences from the currently deployed weights on recent bars. This prevents outdated signals from lingering on the chart and ensures the displayed set matches what a live re-render would produce.
PersistWeightsOnShutdown now returns early when m_inferenceOnly is true,
preventing the tester cache from being overwritten with untrained state.
InitNeuralNetwork compares modification timestamps of the production model
(FILE_COMMON) and the agent-local cache, re-seeding when the production
copy is newer. This ensures backtests always run the latest deployed
weights even when the cache file persists across runs. Also moved
LoadChartSignals() call to after the config fingerprint is appended,
so that persisted arrows are correctly keyed per configuration.
Add FILE_SHARE_READ and FILE_SHARE_WRITE to all FileOpen calls in CNet::Load,
CNet::LoadCheckpoint, and in ExpertSignalAIBase (LoadModelStats, LoadChartSignals)
so that reading model files does not fail with error 5004 when another process
(e.g., a live chart) holds the file. Replace FileCopy with the new CopySharedFile
function for sidecar files (.cfg, .stats, _shadow.nnw) to perform share-aware
copying, preventing the same failure during tester seeding. This ensures the EA
can read and copy model artifacts even while a deployed instance is running.
Replace fixed short-delay retries in CopyFileWithRetry and LoadNetWithRetry with exponential backoff (8 attempts, cap at 2s) to reliably handle transient file locks from AV/EDR or concurrent saves.
Change autosave trigger from a fixed 300-second wall-clock timer to firing on new bar close, reducing unnecessary overwrites and narrowing the collision window with backtest FileCopy operations.
Add retry logic (CopyFileWithRetry, LoadNetWithRetry) to the tester's seeding path in ExpertSignalAIBase.mqh, and print diagnostic error messages in CNet::Load (Network.mqh) when FileOpen fails. This addresses silent failures caused by transient Windows sharing violations that occur when a live chart's atomic Save() overlaps with a Strategy Tester agent's FileCopy or FileOpen on the same production file. The new helpers retry the operation a few times with a short pause instead of silently falling back to an untrained model.
The previous TP calculation used ATR from entry, decoupled from the swing-anchored SL distance. This caused the Min_Risk_Reward_Ratio rejection filter to always fail because reward < 2*risk with default settings, preventing any trades. Now TP is a multiple of the actual trade risk (entry-to-stop distance), restoring coupling and ensuring the default RR filter is satisfiable. Also enforce minimum SL distance before TP calculation to maintain correct risk-ratio.
The queue duplicates minority bars up to repCount (~21x at 30.7:1 imbalance), causing IS accuracy to be scored over an ~58%-directional set while OOS counts the real ~6% distribution. This made the IS/OOS gap misleading (e.g. 77% vs 12%), appearing as catastrophic overfitting when OOS was actually stronger (1.97x vs 1.33x lift). By marking only the first occurrence per bar with `m_isTrainQueuePrimary` and using that flag in the counter, both metrics now measure the same natural class distribution, making the gap directly interpretable as generalization. Backprop and training remain unaffected—every occurrence still trains as before.
Extract shared persistence logic into PersistDeployedModel() to guarantee consistency across all deploy paths (ladder, era-cap, stop, and manual). Add DeployNow() to let the panel button finalize the current best checkpoint as the live model, and RetrainDeployed() to revert deployment and resume training from the deployed weights without starting from scratch. This enables operator-controlled deployment while preserving online continual learning.
Implement a plateau detection mechanism that escalates through warm restart, gamma annealing, and eventual deployment when balanced accuracy stagnates for `PLATEAU_PATIENCE_ERAS`. Also add a compatibility shim for the removed `MinWR` input to preserve model filenames and `.cfg` layout.
A single EA run instantiates several CNet objects (main net, EMA shadow, OOS clones, etc.). Each previously ran its own OpenCL/DirectML probe, printing redundant error banners (e.g., "OpenCL not found") and compute tier messages.
Added process-wide static flags `s_openclUnavailable` and `s_computeTierLogged` to skip subsequent probes and log once per process. This eliminates log clutter and avoids unnecessary probe overhead on hosts without OpenCL.
Rename the original `CreateElement` with a defaulted `weighScale` parameter to `CreateElementScaled` and provide a proper virtual override that matches the base `CArrayObj::CreateElement` signature exactly. This ensures `CArrayObj::Load()` dispatches correctly, fixing a bug where every saved model load failed at the first layer. Update all call sites in `CNeuronBase::Init` and `CNeuronPool::Init`. Additionally, enhance error diagnostics in `CNet::Load` to distinguish between file truncation and code faults (such as the signature mismatch).
The `Load` method now accepts an optional `quiet` flag that suppresses diagnostic
`Print` statements when set to `true`. This is used by callers that anticipate
a load failure and handle it gracefully — for example, the EMA shadow-net
bootstrap on a CPU-DLL box, which cannot hold a second full network. The main
model load keeps `quiet=false` so actual failures remain visible.
- In Network.mqh: Add upfront file size check to distinguish truncated files from backend allocation failures during model load, improving error diagnosis.
- In ExpertSignalAIBase.mqh: Remove redundant shadow net save on shutdown to avoid doubling shutdown cost and exceeding MT5's deinit budget, preventing abnormal termination and subsequent retrain.
- In Warrior_EA.mq5: Reduce training timer interval from 5s to 250ms to allow more frequent training cycles instead of sitting idle ~98% of the time.
The previous save directly wrote to the target file, which could leave a truncated/partial file if the process was force-killed (e.g., MT5 deinit timeout). Now the save writes to a temporary file (.savetmp) and only renames it over the real file after a successful write. This ensures that an interrupted save never corrupts the last good model. Additionally, improved diagnostics in CNet::Load to distinguish corrupt/incompatible files from compute errors.
Updated comments across ExpertSignalAIBase.mqh to explicitly state that the
compounded accuracy metric is a directional win-rate (Buy/Sell predictions only)
and that neutral/no-trade calls are excluded to avoid inflating the rate (since
neutral is the ~94% majority). The cumulative counters now only increment when
the prediction is directional, ensuring the panel reflects genuine trade quality
rather than overall label accuracy.
Replace the display-only MIN_FIRED_FOR_HITRATE with persistent cumulative accuracy counters (m_cumIsCorrect, m_cumIsTotal, m_cumOosCorrect, m_cumOosTotal) that survive era-to-era and restart via .stats. New ComputeCompoundedAccuracyLine() builds the panel line from these counts, providing a stable "accuracy over all validated signals so far" metric.
Split `PersistOnShutdown` into `PersistWeightsOnShutdown` (heavy weights save) and `ShutdownChartCleanup` (save arrows + purge chart). In `OnDeinit`, run panel destruction and per‑signal chart cleanup **before** the weight persistence, preventing leftover chart objects when the weight save stalls or faults past MT5's deinit budget.
Add MIN_FIRED_FOR_HITRATE constant (10) to the simple panel and training status hit-rate display. Update ScheduleTrainingIfNeeded and UpdateTrainingStatusLabel to only show a percentage when a side has at least MIN_FIRED_FOR_HITRATE live-fired calls; otherwise show "n/a" or "measuring". This prevents misleading early "0%" or "measuring" output from a single sample, while keeping full detail in logs and verbose panel.
- ResetWeights now passes `false` (not `m_isInitialized`) to SaveTopologyConfiguration so the config fingerprint matches the fresh-init write (always false). Prevents spurious "Configuration mismatch" that would discard the just-reset weights.
- UpdateTrainingStatusLabel: collapse hit-rate display to "measuring..." when neither side has fired yet; once at least one side fired, show both with "n/a" for missing side.
Add CaptureWeights and RestoreWeights methods that snapshot every neuron's weights into host arrays (CArrayDouble per neuron) and restore them in-place via setWeights. This replaces the file-based SaveCheckpoint/LoadCheckpoint for the mid-run best-era rollback, because the file path re-creates neurons (CLayer+Init) which fails on the multithreaded CPU-DLL backend (CDirectMLMy/WarriorCPU.dll) that cannot allocate a second full set of neuron tensors while the live set exists. In-memory weight copy uses only getWeights/setWeights, already proven by the per-era shadow blend. Snapshots weights only (not Adam moments); the regression handler decays eta on restore and clips per-step deltas to prevent stale-moment overshoot. Snapshot is valid only within a single Train() run. Also adds HaveWeightSnapshot() query and the m_weightSnapshot / m_haveWeightSnapshot member variables.
SaveCheckpoint and LoadCheckpoint in Network.mqh now accept a `bool common` flag. When true, the ephemeral checkpoint is stored in FILE_COMMON (co-located with the model's .nnw/.cfg/.stats/_shadow.nnw), preventing a parallel folder tree under the terminal-local Files directory. ExpertSignalAIBase.mqh is updated to pass the same flag to file existence checks and deletions, ensuring all sidecar files use the correct location.
A failed load of a corrupt/empty network could leave trainingComplete=true, causing the freshly built topology to be treated as already converged. This forced the model to never train, run inference on random weights, and delete all chart arrows. The fix ensures the state is reset to a genuine fresh start so BuildFreshTopology() actually gets trained.
- Guard CNet::Save to refuse writing a 0-layer network (prevents overwriting ~18MB model with empty stub)
- In CNet::Load and LoadCheckpoint, treat 0-layer files as load failure (older stubs still on disk)
- Introduce LOGIT_PRIOR_STRENGTH_PRESETS enum (0–100%) to control logit adjustment tau
- Prepare member variables and AdjustedSignalFromSoftmax for prior-corrected posterior at inference
- Ensure raw argmax scoring for recall/convergence remains unchanged; correction only affects live signal
Add `MA_TYPE_PRESETS` enum covering advanced (ALMA, DEMA, ZLEMA, T3, Kalman) and standard (SMA, EMA, SMMA, LWMA) moving averages. Integrate `maType` and `bestMaType` into `CADIndicatorTuner` struct, update flatten/unflatten routines, and bump `AD_TUNE_PARAM_COUNT` to 33. This allows the auto-tuner to search over MA type alongside period, improving feature discovery.
Replace single `m_pattern_0` weight with four confidence-tier weights (`m_pattern_0` through `m_pattern_3`) so that `UpdateSignalsWeights()` blends across multiple patterns like classic indicators. Previously, a single pattern caused the same win rate to be written to both the pattern weight and module weight, resulting in a quadratic derating (e.g., 70% win rate scored as 49 instead of 70). The new tiers bucket confidence into four equal bands between the minimum AI confidence and 1.0, with defaults 80/87/93/100. Added `ConfidenceTier()` and `PatternWeightForTier()` helpers, and changed default pattern count from 1 to 4.
- Added optional `weighScale` parameter (default -1.0) to `CNeuronBase::Init` and `CLayer::CreateElement`.
- Updated `CNeuronPool::Init` to use LeCun-uniform scaling (1/sqrt(window+1)) for its base initialization.
- Updated `CNet::CNet` to use He-scaled initialization (sqrt(2/neurons)) for dense layers.
- These changes enable more flexible and statistically sound weight initialization, matching the rationale used in OCL-based implementations, leading to better training stability and convergence.
Remove verbose book references from input parameter comments in
Network.mqh for clarity. Add #ifndef guard around ENUM_OPTIMIZATION
to allow inclusion from multiple headers without redefinition.
Document the MQL5 Market DLL restriction in NeuronDirectML.mqh and
introduce WARRIOR_MARKET_BUILD macro to conditionally compile out
DirectML DLL imports for Market-compliant builds.
Replace old ATR_MULTIPLIER, THRESHOLDS_PRESET enums with new
STOP_LOSS_MODE, TAKE_PROFIT_MODE, AI_EXIT_MODE enums that support
ATR-based, intelligent confidence-scaled, and swing-anchored modes.
Also fix LSTM signal identity string.
When `m_signalClusterWindow > 0`, training passes (1,2,3) now only record signal scores into `m_arrowSignalCache[]` and skip drawing arrows. The end-of-era `PruneDirectionalClusters()` sweep handles all rendering, preventing raw mid-era clusters from appearing and decoupling NMS from pass 2’s shuffled draw order.
Change the non-maximum suppression algorithm so that same-direction
contiguous runs collapse to a single arrow by tracking the last SEEN
bar (instead of the last KEPT bar), preventing re-emission every
window+1 bars inside a long run. Add confidence-based resolution
between opposite signals within the cluster window: only the higher-
confidence side is kept, reducing flicker around genuine turn zones.
Introduce new state variables (`m_nmsLiveBuyAccept`,
`m_nmsLiveSellAccept`, `m_nmsLiveKeptTime`, `m_nmsLiveKeptDir`,
`m_nmsLiveKeptConf`) to support idempotent re-evaluation of the same
live bar and cross-direction filtering. Update `NmsLiveAccept` and
`PruneDirectionalClusters` to apply the same logic consistently for
both historical and live paths.
Implement non-max suppression (NMS) to declutter signal visualizations by keeping only the first bar of each same-direction run, controlled by m_signalClusterWindow. Also replace blended accuracy with balanced accuracy (macro-recall) for checkpoint selection to avoid neutral bias, tracked via m_bestBalancedOos. This improves signal clarity and model deployment quality.
Increase the swing context neuron count from 5 to 9 by adding four fresh, non-repainting features: Donchian range position at 20 and 50 bars, 20-bar return, and 20-bar SMA extension. These are computed from closed bars only, eliminating lookahead. They provide immediate trend/position context that the stale (~100-bar-old) confirmed pivot anchor cannot, enabling the network to differentiate genuine reversals at range extremes from mid-trend bars that resemble pivot shapes.
Introduce OVERSAMPLE_PARITY_FRACTION (0.7) to control minority class oversampling scaling, reducing low-quality directional calls by not fully replicating to parity. Add m_minSignalConfidence (0.5) to require a minimum softmax probability for live Buy/Sell orders, preventing firing on bare plurality (~0.34) and improving signal quality.
- Increased MAX_OVERSAMPLE_REPLICAS from 5 to 100 to serve only as an absolute sanity ceiling against degenerate tallies, not a binding limit – oversampling rate is now measurement-driven per era.
- Reverted LABEL_WINDOW_BARS to 0 (exact reversal candle only), as the earlier low recall motivating widening was observed on a flawed training stack that has since been fixed; exact labels get a clean re-test.
- Removed ArrayResize calls in Train that preallocated queues using MAX_OVERSAMPLE_REPLICAS, consistent with the shift to dynamic, measurement-based allocation.
When a new candle closes mid-run (e.g., after weekend market reopen), the label cache is
wiped and the fallback per-bar computation labels everything Neutral. Without this fix,
the rest of the training run silently trains and scores against an all-Neutral world,
causing false convergence (e.g., 84.9% accuracy with 100% Neutral truth). Now the
prebuild is re-armed after cache invalidation to defer the era until relabeling completes,
and convergence finalization requires directional recall to be actually measured (not n/a),
preventing a Neutral-only model from being certified.
Also improves logging to distinguish era 0 seeding from mid-run rebuilds.
Reduce weight decay from 0.01 to 0.001 across all backends (Network.cl, Network.mqh, WarriorCPU.cpp) to fix a training collapse issue. The original 0.01 AdamW default caused discriminative weights to decay below the calibration-capped class-prior offsets, resulting in a monotonically shrinking per-bar logit spread and eventual constant Neutral predictions (argmax degenerated once evidence tilt dropped under the prior tilt). The new value 0.001 lifts the evidence ceiling 10× while still bounding long-run weight growth, restoring effective discrimination. Note: this change must remain in sync across all four backends.
The sign-agreement gate in `UpdateWeightsAdam`, `UpdateWeightsConvAdam`, and `LSTM_UpdateWeightsAdam` caused a gradient ratchet effect under one-hot softmax with categorical cross-entropy, leading to an all-Neutral collapse. Removing this gate aligns all four backends (CPU, GPU, OpenCL, MQL) and restores correct gradient flow.
Introduce m_useSwingContext flag and FindConfirmedZigZagPivot method to compute normalized swing direction/magnitude/age features from the existing ADZigZag indicator. Only pivots that are at least m_swingConfirmationBars old are trusted, preventing lookahead bias. The SWING_SCAN_CAP_BARS macro limits backward scan depth. Default is off.
Remove overly verbose explanations in Network.mqh comments and InputEnums.mqh enum values. Shorten descriptions to improve readability without losing essential information.
Class-balance correction is now performed entirely via data-level oversampling (duplicating minority-class bars) instead of using a per-occurrence loss-weight multiplier combined with oversampling. The loss-weight mechanism proved ineffective due to Adam's near-invariance to constant gradient rescaling (Kingma & Ba 2015). The CLASS_SAMPLE_WEIGHT_PRESET enum is retained for a possible future supplemental loss weight, but m_maxClassSampleWeight currently has no effect. The MAX_OVERSAMPLE_REPLICAS constant is now the sole bound on correction strength.
Updated comments in InputEnums.mqh and ExpertSignalAIBase.mqh to reflect this change.
- Clarify MAX_OVERSAMPLE_REPLICAS comment: it is an outer safety cap; actual repCount is derived from m_maxClassSampleWeight.
- Introduce m_isTrainQueueWeightScale array to scale per-occurrence class-balance weight by repCount, avoiding independent compounding of frequency and magnitude.
- Add forceRefresh flag to UpdateTrainingStatusLabel to force panel update at era end, fixing one-era-behind display of era number.
Introduce MAX_OVERSAMPLE_REPLICAS=3 to duplicate minority-class (Buy/Sell) bars in the training queue, complementing the existing loss-level reweighting. Adam's update rule largely cancels gradient scaling, so pure loss weighting was insufficient to overcome class imbalance. Duplicating bars ensures Adam's moment estimates see minority gradients more frequently, preventing the Neutral-only collapse observed in practice.
Optimize() scaled lot size off account trade-history streaks with no Magic-number
filter (picked up other EAs'/manual trades) and an unconfigurable m_factor stuck at
1.0 (Factor() was never wired from an input), so a 3-trade streak could triple lot
size or send it negative. It was also entirely disconnected from what the AI model
actually knows about the current setup.
Replaced both AdjustRiskAmount()'s linear confidence-only scale and Optimize()'s
streak multiplier with one edge-based model: p from the empirically calibrated
AI/DB confidence magnitude, b from the trade's real reward:risk ratio (newly
bridged from OpenParams() via g_TradeRewardRiskRatio), quarter-Kelly applied and
clamped so risk% can only ever scale down from its configured ceiling, never above it.
Price, time, volume, and volatility were already trained-model input
features; the real economic calendar (already used for the live
NewsFilter veto) is now an optional one too, reusing
System/NewsRelevance.mqh's symbol-relevance logic from the prior fix.
New EnableNews/NewsFeatureWindowMinutes inputs gate two features per
bar: minutes-since and minutes-until the nearest symbol-relevant
calendar event, impact-weighted. Deliberately limited to proximity +
impact, not actual-vs-forecast deviation - release schedules are
public knowledge ahead of time (not lookahead bias to use for a
historical training bar), but a release's actual outcome is not.
Wired identically to the existing EnableVolume/EnableTime/EnableATR
toggles: InitIndicators() accounts for the +2 neuron count,
BufferTempDataCompute() appends the two feature values, PAI/CONV/LSTM
all wired in Warrior_EA.mq5. Compiled clean (MetaEditor, 0 errors/0
warnings).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
CExpertSignalAIBase (4,326 lines, one class) carried 5 struct
definitions, 10 member fields, and 3 methods (Flatten/Unflatten/
PerturbRandom) purely for the AutoTuneIndicators search-space state -
entirely self-contained (never touches Net, Train()'s resumable state
machine, or anything else in the class). Extracted into a new
Expert/ADIndicatorTuner.mqh (CADIndicatorTuner), held as a single
m_indicatorTuner member.
TuneIndicatorsAndTrain() itself - the outer loop that actually
orchestrates Train()/Net/checkpointing around this tuner - turned out
to be exactly as tightly coupled to Train()'s resumable state machine
as Train() itself, so per the same caution already applied to Train()
in this refactor pass, it stays in CExpertSignalAIBase rather than
being pulled into the collaborator; it now calls the tuner's public
Flatten()/Unflatten()/PerturbRandom()/SaveAsBest()/RestoreBest()
instead of manipulating the structs inline.
All internal field-access renames (m_adCumDeltaParams.lookback ->
m_indicatorTuner.adCumDelta.lookback, etc., ~40 sites across the 5
InitAD*() indicator-setup methods) verified against a full grep sweep
- no leftover references to the old field/method names. Compiled
clean (MetaEditor, 0 errors/0 warnings).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>