Moving the per-bar window/feedForward step before the label-check/backprop
step (previous commit) meant the label-check block now runs LAST each
iteration, clearing TempData and refilling it with the smoothed target label
(0.1/0.9) for backProp - so by the time the next iteration's Comment() call
read TempData[0..2] to display "Buy/Sell/Neutral Neuron", it was showing the
PREVIOUS bar's true label, not the network's actual prediction. Since ~94% of
bars are Neutral-labeled, this mostly looked like "Neutral stuck near 0.9-1,
Buy/Sell stuck near 0.1" regardless of what the model was really outputting.
Snapshot the softmax probabilities into local vars right after they're
computed (before the label-check block can clobber TempData), and moved the
whole Comment() build to run right after that snapshot instead of at the top
of the loop, so it now shows the CURRENT bar's own genuine prediction.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
RefreshLatestSignal(), AdvanceOosSimulationChunk(), and Train()'s per-bar window
build all constructed the historyBars-wide feature window starting historyBars
bars past the target bar (r = i + historyBars) instead of ending at it (r = i) -
so the model was always blind to the most recent historyBars bars of price
action right before the bar it was being asked to call, both in training and
live inference. This likely explains why Buy calls fire but land poorly timed
and Sell almost never clears its recall floor.
Also reordered Train()'s main loop so each bar's own freshly-built window/
prediction is what gets checked against that bar's label immediately (matching
AdvanceOosSimulationChunk's existing predict-then-learn pattern), instead of
training against the previous iteration's stale prediction.
Also added a Print() when training genuinely converges (m_objectiveMet &&
m_oosStable) - this was previously silent, only visible via the persisted
TrainingComplete flag.
Existing trained weights encode the old, shifted task and need a full retrain.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
TargetCPULoad=max was only ever getting ~half the cores (e.g. 6 of 12)
even outside HYBRID mode, because every CNet (including the live net's
own EMA shadow net, which every signal has) counted as a "peer" that
divided the requested CPU budget.
That division was solving a problem that can't actually happen: MQL5
gives one chart's EA a single execution thread, and every WarriorCPU.dll
entry point blocks that thread until its own ParallelFor() completes,
so only one CNet's worker pool is ever actively computing regardless of
how many are alive (live, shadow, or - under HYBRID - PAI/CONV/LSTM's
own pairs). The idle ones sit blocked on a condvar at ~0% CPU. Dividing
the budget across "peers" that never contend just capped whichever pool
happened to be running at a fraction of the cores actually available.
Removes the now-pointless g_netPeerCount/EffectiveCpuLoadPercent()/
PeerNetworkCount() machinery entirely; SetCpuLoadPercent() now just
takes TargetCPULoad directly.
Recall (directionalRecallOK) was only ever printed on a regression
event, so once OOS accuracy alone cleared the target there was no way
to tell from the Journal whether recall was the thing still blocking
m_objectiveMet. Now shown on every ~5s progress line.
Two issues compounded to keep the network oscillating for 350+ eras
without ever reaching m_objectiveMet, despite good OOS accuracy:
- CNet::backPropOCL() zeroed the diagnostic error contribution from
any output neuron whose target was exactly 0, unlike backProp()'s
CPU-fallback path. For the one-hot 3-class classification head this
meant dError only ever reflected the true class's own calibration,
never whether the other two classes were correctly suppressed -
purely a reporting bug, the real gradient (CPU_CalcOutputGradient
in WarriorCPU.cpp) was already correct and unaffected.
- Train()'s convergence gate required dError < 0.1 unconditionally.
That RMS-error floor is reachable for the single-neuron regression
head, but for 3 one-hot outputs it demands near-perfect confident
calibration on every bar - unreachable under normal market label
noise, and redundant with the classification-native gates already
in place (dOosForecast >= target, per-class directionalRecallOK).
Now skipped when m_outputNeuronsCount == 3.
Origin's f115453 (neuron-reduction-factor fix + fractal/deviation-based
ZigZag labeling inputs) predates and is fully superseded by the local
switch to the real ADZigZag indicator for training labels - resolved by
keeping HEAD's version throughout.
- Remove manual Expert.Deinit() calls from all failure branches in OnInit() because MQL5 automatically calls OnDeinit(REASON_INITFAILED) when returning non-INIT_SUCCEEDED, preventing double deinitialization and invalid pointer access in OnDeinit().
- Change ADZigZag buffer count from 1 to 3 to match the indicator's #property indicator_buffers (3 buffers), accounting for internal INDICATOR_CALCULATIONS buffers, consistent with other AD Wyckoff indicators.
- Replace the hand-rolled fractal/deviation-%/ATR-trend-context ZigZag
approximation with the actual MQL5 ZigZag indicator (rebranded as
CustomIndicators/ADZigZag.mq5, logic untouched) as the training label
source; bump the settle/confirmation window from 20 to 100 bars so a
proper leg can form before being trusted, and drop the now-dead
ZigZagDeviationPct/MinTrendATRMultiple/TrendContextBars inputs.
- Rebrand the stock Volumes indicator the same way (ADVolume.mq5).
- Fix HYBRID mode (AIType=HYBRID) oversubscribing the CPU fallback tier:
every concurrent CNet instance was independently sizing its worker
pool off the same global TargetCPULoad input. g_netPeerCount/
PeerNetworkCount() now split it across however many CNet instances
(live+shadow x active signals) are actually sharing the CPU.
- Fix NEURONS_REDUCTION_FACTOR's confusing retention-vs-reduction
semantics so RF_70 means an actual 70% reduction; default to 4 hidden
layers / RF_70.
- Migrate remaining free-form training/indicator inputs to enums for UI
consistency; default news filter lookback to 1h, disable every-tick.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Fix neuron retention calculation in `BuildFreshTopology()` to use the complement of reduction percentage (retention = 100 - reduction) instead of directly applying the reduction value.
- Correct `NEURONS_REDUCTION_FACTOR` enum descriptions to accurately reflect the actual reduction percentage (e.g., RF_10 now reads "10 % Neurons Reduction Per Layer").
- Add new enums: `ZIGZAG_DEVIATION_PRESET`, `SWING_CONFIRMATION_PRESET`, `TREND_ATR_MULTIPLE_PRESET`, `TREND_CONTEXT_BARS_PRESET`, `MAX_ERAS_PRESET`, `RETRY_COOLDOWN_PRESET`, `TUNE_TRIALS_PRESET` for finer-grained configuration.
- Tighten MAX_WEIGHT from 1.0e6 to 100.0 to prevent unbounded weight growth.
- Add MIN_ACTIVATION_DERIVATIVE (1e-4) to avoid zero gradients for saturated units.
- Introduce WEIGHT_DECAY (0.01) to decouple decay from Adam updates.
- Add MAX_WEIGHT_DELTA (0.1) to clamp per-step Adam updates and prevent overshoot.
- Apply sign-agreement gate on weight updates in Adam kernel to only apply steps aligned with current gradient direction.
- Fix tanh/sigmoid derivative calculations to use the new floor instead of hard-coded edge-case values.
- In CaclOutputGradient kernel:
- Case 1 (sigmoid classification): removed erroneous multiplication by out*(1-out) which dampened gradients – the binary cross-entropy loss already cancels the sigmoid derivative, so direct (target-out) is correct.
- Added default case for NONE activation (softmax classification) to compute plain error (target-out); previously unhandled, resulting in zero gradients that froze the entire network when OpenCL was active.
- In UpdateWeightsMomentum and UpdateWeightsAdam kernels: added clamp to MAX_WEIGHT when updating weights to prevent gradient spikes from producing ±Infinity and subsequent NaN propagation through dense layers (e.g., classification output head).
- Introduce per-bar feature cache to avoid redundant recomputation of input vectors during training.
- Rename EnsureLabelCacheCapacity to EnsureBarCachesCapacity to reflect management of both label and feature caches.
- Fix oversampling logic to maintain balanced representation among minority classes, replacing independent 5x caps that caused relative bias.
Warrior_EA.mq5: clear Comment() and destroy the control panel before
Expert.Deinit()'s object-purge cascade runs out from under it; stop
re-registering the same signal filters on every DB retry (was causing a
double-delete of the same pointer on shutdown).
DirectML/WarriorCPU.cpp: bound the worker-thread join in ThreadPool::Stop()
instead of blocking forever - CPU_Shutdown() held g_mutex across an unbounded
join, so a watchdog-killed calling thread could leave it locked forever,
poisoning every future call into the DLL (matches reports of the EA getting
stuck on "initializing" after being removed and re-added to a chart).
Also includes prior era-0 label-cache prebuild and pullback/reversal
label-quality work in AI/Network.mqh, Expert/ExpertSignalAIBase.mqh, and
Variables/Inputs.mqh.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replace the absolute thread count input (CpuDllThreads) with a percentage-based CPU_LOAD_PRESET enum (TargetCPULoad). This allows users to specify a percentage of detected cores to use when the CPU DLL fallback is active, improving flexibility and preventing issues when multiple instances share the same CPU DLL pool. Also adds CPU_GetHardwareConcurrency() for accurate core detection.
Changed default HiddenLayersCount from LAYERS_5 to LAYERS_3 and NeuronsReduction from RF_80 to RF_60 to improve model generalization and reduce overfitting.
MQL5 refuses to compile `#resource` directives pointing to PE executables ("unsupported resource type ... executable file prohibited"). This commit removes the `#resource` lines and the `ExtractComputeDlls()` function from `AI/Network.mqh`, and updates comments in `Warrior_EA.mq5` to explain that the DLLs must be manually placed in `MQL5\Libraries\`. The call to `ExtractComputeDlls()` in `OnInit()` is also removed.
Add #resource directives for WarriorDML.dll and WarriorCPU.dll, and ExtractComputeDlls() to extract them on first run, enabling MQL Cloud Protector builds to ship DLLs without manual copy. Extend CNet::Save and Load with trainingComplete and indicatorParams arrays to persist AutoTune indicator param values.
The TANH activation's derivative (1-out^2) approaches zero when the output nears ±1, stalling training exactly where convergence to extreme values (e.g., buy/sell signals) is needed. Removing the multiplication by this derivative in the output gradient calculation (both CPU OpenCL and MQL4 paths) prevents this saturation, analogous to using cross-entropy with sigmoid.
Additionally, extend `Save()` and `Load()` to include a new `era` field, enabling tracking of training generations across sessions.
- Define MAX_WEIGHT constant (1.0e6) for weight limits in clusters
- Remove redundant barrier from FeedForward kernel (prevents sync issues)
- Port FeedForwardProof and CalcInputGradientProof kernels for max-pooling (no weights, sliding max)
- Port FeedForwardConv kernel for convolution layers (shared weights, multiple output channels)
- Remove unused code and refactor signal condition logic (CSignalPAI)
- Updated README.md with project overview, key features, directory structure, getting started guide, and modernization roadmap.
- Added AI_NETWORK.md detailing the neural network and AI/ML infrastructure, including architecture, components, usage patterns, and next steps.
- Introduced DATABASE.md for the Database module, outlining key components, design highlights, usage patterns, and future enhancements.
- Created README.md files for Enumerations, Expert, Money, Signals, Structures, System, Trailing, Variables directories, detailing their purpose, key components, and integration notes.
- Documented the Signals subsystem, emphasizing modularity, extensibility, and AI/ML readiness.
- Added comprehensive descriptions for individual signal modules in Signals/ directory.
- Established clear integration notes and recommendations for future improvements across all modules.