- Replaced standard library signal modules with custom implementations to allow for named patterns and improved voting.
- Added new input parameters for module weights, allowing for optimization of individual signal contributions.
- Enhanced the management of trades with new options for breakeven and management cut.
- Introduced a mechanism for dynamic ranking of signal weights based on historical performance.
- Improved initialization logic to ensure proper registration of filters and handling of trading conditions.
- Added detailed logging for trading permissions and account status during initialization.
WHAT AND WHY. ed91919 removed the four classic votes because all 26 patterns measured AT CHANCE as
standalone entries - pre-registered, nothing fitted, and the +4 sigma that had once appeared was two
bars of lookahead. That result stands. It is also not the claim being made here.
That test measured UNCONDITIONAL edge: fired blind, does this pattern beat a coin on average. No -
after the lookahead fix MACD_p4 read -0.02pp at -0.02 sigma, flat rather than weak. A signal that is
zero on average can still be strongly positive on a SUBSET, and finding that subset is exactly what
meta-labelling is for. The primary supplies direction and an entry BAR and is judged on RECALL; the
net decides which firings to take.
THE MEASURED PROBLEM THIS ATTACKS. Under the leg-ride label the primary was "the ZigZag leg in
progress", so entry landed on an ARBITRARY bar inside a move already underway. Measured 2026-09-05
on the converged fleet: the ORACLE ride is +4.2 to +4.6 ATR per leg on every chart, and the models
captured +0.08 to +0.38 over a 14-17 bar hold - under 10%, because most of the leg was gone before
entry. Always-ride scores -0.14 to +0.10, i.e. an arbitrary entry inside a leg is worth nothing. A
pattern fires at a CHOSEN bar with the move ahead of it.
RESTORED: SignalMA (4 patterns), SignalRSI (4), SignalMACD (6), SignalIchimoku (12),
OscillatorDivergence, plus Bill Williams SignalAO (4) and SignalAC (3) recovered from 1073262.
33 patterns across six voting modules. The only edit needed was dropping SweepPrepareIndicator(),
whose base-class method no longer exists.
THE WEIGHTS ARE FIXED PRIORS (Variables\ClassicSignals.mqh), set from structural strength and rarity
in the spirit of the standard library's own ladder, NOT fitted to returns:
10 confirming state ("price is on the right side") - every module's pattern 0
15-30 simple state or weak-grade event (overbought reversal, cross in a poor location)
30-50 a crossing or completed pull-back
50-70 structural: divergence, cloud breakout, strong-grade cross
80-100 rare confluence: double divergence (90), Sanyaku Kouten (95)
33 numbers tuned against measured returns would be 33 free parameters and would hand back the
family-wise problem this project keeps rediscovering. They are priors and must stay priors.
AND THE FEEDBACK LOOP IS CUT. DB_RankingFeedsWeights=false splits the signal database in two:
ProcessBufferedSignals() still RECORDS every firing, direction, entry, exit and outcome - that
corpus is the input to the meta-labelling work - while UpdateSignalsWeights() no longer writes win
rates back into the pattern weights. That loop is why the classic votes were never evaluable: the
same setup contributed a different amount at different times, so the vote drifted era to era under
the model and nothing could be measured against it. UseDatabaseRanking gates BOTH halves, so turning
the master switch off would have stopped the collection too.
RARITY CUTS BOTH WAYS, recorded rather than glossed: double divergence earns 90 BECAUSE it is rare,
which also means the net will see very few examples and can say little about it. The prior carries
those patterns; the model will learn mostly about the common, low-weight ones.
Compiles clean. Not yet deployed - the Bill Williams suite (Alligator, Fractals, Gator, BWMFI) and
the stdlib ports land next, and one restart should carry all of it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
research/classic.py transcribed all 26 shipped vote patterns (MA 4, RSI 4, MACD 6,
Ichimoku 12) with their constructor weights and tested them as entries on 178k-bar
histories, four instruments x three barrier geometries. Nothing separated from
chance - not one pattern, not the averaged vote at any threshold 10-70, not a
2/3/4-module quorum, not event-plus-confirmation. Residual E[R] everywhere was
-0.01 to -0.08 R, which is approximately the spread. The +4 sigma reading that had
once justified the set was two bars of lookahead: closing it took MACD_p4 on EURUSD
from +5.05pp to -0.02pp.
All four inputs have shipped false ever since, so this deletes dormant code rather
than changing behaviour.
RETRAIN-NEUTRAL, deliberately. EnableMA and EnableRSI were hashed UNCONDITIONALLY
into the DB config fingerprint, so they become literal 0 legacy slots - the same
treatment the ind_Periods slot two lines above already uses, and every existing
database keeps its key. EnableMACD/EnableIchimoku were appended only when enabled,
so with both gone the segment simply never appears, which is byte-identical to
today. No .nnw or .db is orphaned.
WHAT THIS COSTS, STATED PLAINLY: these four were CSignalMETA's only wired candidate
sources, so the on-chart ladder sweep (BuildCorpusBySweep) now has nothing to sweep
and a META chart is no longer self-contained. That is survivable rather than fatal
because MetaPrepareEra already falls back to CMetaCorpus::LoadLargestOnDisk, and its
own comment names this exact case - "charts whose classic filters are disabled".
Use_MetaLabeling ships false regardless. SignalMETA.mqh is otherwise UNTOUCHED, and
its 26-slot one-hot stays at 26: a tester-built corpus on disk still encodes those
pattern ids, and narrowing the descriptor would invalidate every stored corpus.
Signals/SignalMA.mqh SignalRSI.mqh SignalMACD.mqh SignalIchimoku.mqh deleted
Signals/OscillatorDivergence.mqh deleted - RSI and MACD were its only users
Classic_Shift deleted - the four votes were its only readers
Compile-verified in the stage copy: 0 errors, 0 warnings, against a 0/0 baseline
taken before any edit.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
StateRSI/StateMain, ExtStateRSI/ExtState, and CompareMaps were duplicated
verbatim (~110 lines each, even the comments) between SignalRSI.mqh and
SignalMACD.mqh - the only real difference was the oscillator value source
(RSI(pos) vs Main(pos)). Neither method touches the pattern-weight fields
LongCondition/ShortCondition read, so unlike the previously-declined
ApplyPatternWeight dedup, this extraction needed no change to the live
voting logic itself - only the ExtState(idx)/CompareMaps(...) call sites
now go through the shared collaborator.
New Signals/OscillatorDivergence.mqh: IOscillatorDivergenceSource
(abstract - oscillator value + price low/high extremum lookup) and
CDivergenceDetector (owns m_extr_osc/pr/pos/map as real members, STATEFUL,
fully exclusive - grep-confirmed no reader outside the old per-class
copies). MQL5 has no multiple inheritance and both signals already extend
CExpertSignalCustom, so each gets a thin CSignalXxxDivergenceSource
adapter (owner pointer + 3 forwards) rather than implementing the view
directly, matching the Expert/* view+adapter pattern. Added 3 small
public DivergenceOscillatorValue/DivergencePriceLow/DivergencePriceHigh
wrappers per class since the adapter is a separate object, not a
subclass, and can't reach RSI()/Main()/m_low/m_high (protected) directly.
Every moved statement verified against the pre-edit body; the only
non-mechanical change is a stale comment ("ExtStateRSI's scan") updated
to the new method name.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>