refactor(topology): split shape derivation into CTopology, leave the boot sequence in place
Expert/AIBase/Topology.mqh (1191 lines) held two genuinely different jobs: the
fingerprint/derived-shape/BuildFreshTopology math, and InitNeuralNetwork/
InitFeatureIndicators - the network boot sequence (config-lock, tester-cache
seeding, load/save the .cfg, net-load backend fallback, chart/persistence/
online-learning orchestration).
Extracted the first job to Expert/Topology/ as CTopology + CTopologyView/
CAIBaseTopologyView (20 methods: BuildModelFingerprint, the Estimated*/Compute*
budget math, the Conv*/Lstm* shape helpers, Add*Stage, BuildFreshTopology).
STATELESS, like ModelPersistence - grep-verified zero exclusive fields, every
member these methods touch is shared elsewhere in the signal. Reused ~15
existing Data*/Chart*/Persist*/Exc* getters per the established convention;
added ~20 new getter overloads next to their existing setters (UseVolumes(),
MinDirectionalRecall(), etc. - same pattern as SignalClusterWindow) and ~16
new Topology*() wrappers for fields with no prior accessor. The Net-pointer
swap in BuildFreshTopology is one consolidated view call
(TopologyReplaceNetFromTopology), same doctrine as Persistence's
RunCpuInferenceSelfCheck - irreducible pointer work, not signal state.
Deliberately did NOT extract InitNeuralNetwork/InitFeatureIndicators: they
orchestrate nearly every other collaborator (chart, persistence, online-
learning, cross-asset, config-lock) rather than deriving a shape, so moving
them would just relocate a hub, not reduce coupling - same judgment call as
Inference.mqh (assessed, not extracted). They stay in the AIBase/Topology.mqh
partial, byte-identical to before (diffed against git HEAD to confirm), and
now call the extracted math through the same public forwards every other
caller already used.
Verified: string- and numeric-literal diff of the old file's 20 method bodies
against the new CTopology methods (0 differences), InitNeuralNetwork/
InitFeatureIndicators byte-identical, self-compiled 0 errors/0 warnings.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-23 23:23:00 -04:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| Warrior_EA |
|
|
|
|
|
//| AnimateDread |
|
|
|
|
|
//| |
|
|
|
|
|
//| CAIBaseTopologyView bodies - needs the full signal declaration. |
|
|
|
|
|
//| Same doctrine as Persistence\AIBasePersistenceViewImpl.mqh - |
|
|
|
|
|
//| every method is a forward, borrowed pointer checked on every |
|
|
|
|
|
//| call. |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
#ifndef WARRIOR_TOPOLOGY_AIBASETOPOLOGYVIEWIMPL_MQH
|
|
|
|
|
#define WARRIOR_TOPOLOGY_AIBASETOPOLOGYVIEWIMPL_MQH
|
|
|
|
|
string CAIBaseTopologyView::Id(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.DataId() : ""; }
|
|
|
|
|
string CAIBaseTopologyView::SymbolName(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.ChartSymbolName() : _Symbol; }
|
|
|
|
|
ENUM_TIMEFRAMES CAIBaseTopologyView::Timeframe(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.ChartTimeframe() : PERIOD_CURRENT; }
|
|
|
|
|
int CAIBaseTopologyView::OptimizationAlgo(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.TopologyOptimizationAlgo() : 0; }
|
|
|
|
|
int CAIBaseTopologyView::OutputNeuronsCount(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.ChartOutputNeuronsCount() : 0; }
|
|
|
|
|
int CAIBaseTopologyView::NeuronsCount(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.DataFeaturesPerBar() : 0; }
|
|
|
|
|
int CAIBaseTopologyView::HistoryBars(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.DataHistoryBars() : 0; }
|
|
|
|
|
int CAIBaseTopologyView::InitialNeuronsCount(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.TopologyInitialNeuronsCount() : 0; }
|
|
|
|
|
int CAIBaseTopologyView::HiddenLayersCount(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.TopologyHiddenLayersCount() : 0; }
|
|
|
|
|
int CAIBaseTopologyView::ConvFilterCount(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.TopologyConvFilterCount() : 0; }
|
|
|
|
|
int CAIBaseTopologyView::LstmHiddenSize(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.TopologyLstmHiddenSize() : 0; }
|
|
|
|
|
int CAIBaseTopologyView::MinTrainYear(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.TopologyMinTrainYear() : 0; }
|
|
|
|
|
int CAIBaseTopologyView::FractalPeriods(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.TopologyFractalPeriods() : 0; }
|
|
|
|
|
int CAIBaseTopologyView::OosSplitPct(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.ChartOosSplitPct() : 0; }
|
|
|
|
|
int CAIBaseTopologyView::SwingConfirmationBars(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.SwingConfirmationBars() : 0; }
|
fix(topology): size the network against observations, not bars
The capacity budget is stated in weights per INDEPENDENT observation
and divides by the mean label lifespan to get there. It never once
did: EstimatedInSampleBars() deflates via m_labelOverlap, but it is
only ever called from InitNeuralNetwork, where the label cache does
not exist yet (that same function sets m_labelCachePrebuilt = false
a few lines below), so MeanLifespan() returned its "nothing measured"
default of 1.0 at every call. Every fresh model was sized as though
its labels did not overlap - over-budgeting the first dense layer by
a factor of L, which is several rungs of a power-of-two ladder. The
"expect overfitting, reduce the feature set or pool instruments"
warning is the branch that should fire on H1 and structurally could
not.
Fixed at the source rather than by reordering the boot sequence (the
prebuild is chunked across Train() calls and cannot complete inside
init): MeasureSwingGeometry() walks the ZigZag ONCE at init and
answers both questions from it - the median leg gives the window,
and the leg series gives the mean label lifespan analytically.
SwingPivotDirectionLabel resolves bar i when the SECOND pivot after
it commits, so a bar d bars before pivot P waits d + (the leg
leaving P); summed over every bar of every leg that is exactly the
mean the label walk accumulates.
That also closes the coherence gap the swing target opened: the
window was measured with a private +/-12-bar fractal while the label
aimed at ZigZag(12,5,3) pivots, so it was sized against a leg
distribution the label never used. One pivot source now, the
label's.
Also:
- ResetWeights() re-derives the shape. It rebuilt from the members a
history-starved init had pinned and re-saved them - so the "let
history download, then reset from the panel" advice in both
fallback warnings did nothing at all.
- The CAPACITY line prints the measured lifespan beside the one the
topology was sized for, and warns when they differ by more than a
ladder rung. That is the check that makes the estimator falsifiable.
- Topology reads the view's symbol, not _Symbol (latent for pooling).
- Unmeasured geometry defaults to HISTORY_BARS_FALLBACK, never 1.0:
under-sizing is recoverable, over-sizing silently is not.
Compile: 0 errors, 0 warnings (stage).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 21:21:05 -04:00
|
|
|
int CAIBaseTopologyView::ZigZagHandle(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.TopologyZigZagHandle() : INVALID_HANDLE; }
|
refactor(topology): split shape derivation into CTopology, leave the boot sequence in place
Expert/AIBase/Topology.mqh (1191 lines) held two genuinely different jobs: the
fingerprint/derived-shape/BuildFreshTopology math, and InitNeuralNetwork/
InitFeatureIndicators - the network boot sequence (config-lock, tester-cache
seeding, load/save the .cfg, net-load backend fallback, chart/persistence/
online-learning orchestration).
Extracted the first job to Expert/Topology/ as CTopology + CTopologyView/
CAIBaseTopologyView (20 methods: BuildModelFingerprint, the Estimated*/Compute*
budget math, the Conv*/Lstm* shape helpers, Add*Stage, BuildFreshTopology).
STATELESS, like ModelPersistence - grep-verified zero exclusive fields, every
member these methods touch is shared elsewhere in the signal. Reused ~15
existing Data*/Chart*/Persist*/Exc* getters per the established convention;
added ~20 new getter overloads next to their existing setters (UseVolumes(),
MinDirectionalRecall(), etc. - same pattern as SignalClusterWindow) and ~16
new Topology*() wrappers for fields with no prior accessor. The Net-pointer
swap in BuildFreshTopology is one consolidated view call
(TopologyReplaceNetFromTopology), same doctrine as Persistence's
RunCpuInferenceSelfCheck - irreducible pointer work, not signal state.
Deliberately did NOT extract InitNeuralNetwork/InitFeatureIndicators: they
orchestrate nearly every other collaborator (chart, persistence, online-
learning, cross-asset, config-lock) rather than deriving a shape, so moving
them would just relocate a hub, not reduce coupling - same judgment call as
Inference.mqh (assessed, not extracted). They stay in the AIBase/Topology.mqh
partial, byte-identical to before (diffed against git HEAD to confirm), and
now call the extracted math through the same public forwards every other
caller already used.
Verified: string- and numeric-literal diff of the old file's 20 method bodies
against the new CTopology methods (0 differences), InitNeuralNetwork/
InitFeatureIndicators byte-identical, self-compiled 0 errors/0 warnings.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-23 23:23:00 -04:00
|
|
|
|
|
|
|
|
bool CAIBaseTopologyView::UseVolumes(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.UseVolumes() : false; }
|
|
|
|
|
bool CAIBaseTopologyView::UseTime(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.UseTime() : false; }
|
|
|
|
|
bool CAIBaseTopologyView::UseATR(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.UseATR() : false; }
|
|
|
|
|
bool CAIBaseTopologyView::UseSwingContext(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.UseSwingContext() : false; }
|
|
|
|
|
bool CAIBaseTopologyView::UseNews(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.UseNews() : false; }
|
|
|
|
|
int CAIBaseTopologyView::NewsFeatureWindowMinutes(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.NewsFeatureWindowMinutes() : 0; }
|
|
|
|
|
bool CAIBaseTopologyView::UseMA(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.UseMA() : false; }
|
|
|
|
|
bool CAIBaseTopologyView::UseCrossAsset(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.UseCrossAsset() : false; }
|
|
|
|
|
bool CAIBaseTopologyView::UseSpreadFeature(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.UseSpreadFeature() : false; }
|
|
|
|
|
bool CAIBaseTopologyView::UseAltData(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.TopologyUseAltData() : false; }
|
|
|
|
|
bool CAIBaseTopologyView::IsEnsembleMember(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.DataIsEnsembleMember() : false; }
|
2026-08-25 22:51:50 -04:00
|
|
|
double CAIBaseTopologyView::PooledIndependentBars(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.TopologyPooledIndependentBars() : 0.0; }
|
refactor(topology): split shape derivation into CTopology, leave the boot sequence in place
Expert/AIBase/Topology.mqh (1191 lines) held two genuinely different jobs: the
fingerprint/derived-shape/BuildFreshTopology math, and InitNeuralNetwork/
InitFeatureIndicators - the network boot sequence (config-lock, tester-cache
seeding, load/save the .cfg, net-load backend fallback, chart/persistence/
online-learning orchestration).
Extracted the first job to Expert/Topology/ as CTopology + CTopologyView/
CAIBaseTopologyView (20 methods: BuildModelFingerprint, the Estimated*/Compute*
budget math, the Conv*/Lstm* shape helpers, Add*Stage, BuildFreshTopology).
STATELESS, like ModelPersistence - grep-verified zero exclusive fields, every
member these methods touch is shared elsewhere in the signal. Reused ~15
existing Data*/Chart*/Persist*/Exc* getters per the established convention;
added ~20 new getter overloads next to their existing setters (UseVolumes(),
MinDirectionalRecall(), etc. - same pattern as SignalClusterWindow) and ~16
new Topology*() wrappers for fields with no prior accessor. The Net-pointer
swap in BuildFreshTopology is one consolidated view call
(TopologyReplaceNetFromTopology), same doctrine as Persistence's
RunCpuInferenceSelfCheck - irreducible pointer work, not signal state.
Deliberately did NOT extract InitNeuralNetwork/InitFeatureIndicators: they
orchestrate nearly every other collaborator (chart, persistence, online-
learning, cross-asset, config-lock) rather than deriving a shape, so moving
them would just relocate a hub, not reduce coupling - same judgment call as
Inference.mqh (assessed, not extracted). They stay in the AIBase/Topology.mqh
partial, byte-identical to before (diffed against git HEAD to confirm), and
now call the extracted math through the same public forwards every other
caller already used.
Verified: string- and numeric-literal diff of the old file's 20 method bodies
against the new CTopology methods (0 differences), InitNeuralNetwork/
InitFeatureIndicators byte-identical, self-compiled 0 errors/0 warnings.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-23 23:23:00 -04:00
|
|
|
|
|
|
|
|
bool CAIBaseTopologyView::UsesConvStage(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.PersistUsesConvStage() : false; }
|
|
|
|
|
bool CAIBaseTopologyView::UsesLstmStage(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.TopologyUsesLstmStage() : false; }
|
|
|
|
|
bool CAIBaseTopologyView::HasConvBeforeLstm(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.TopologyHasConvBeforeLstm() : false; }
|
|
|
|
|
bool CAIBaseTopologyView::AddCustomLayers(CArrayObj *topology)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.TopologyAddCustomLayers(topology) : false; }
|
|
|
|
|
ENUM_ACTIVATION CAIBaseTopologyView::HiddenLayerActivation(void)
|
feat(target): delete the barrier/geometry stack - the label is the verdict
Step 3 of the swing-pivot plan, whole-hog. The swing label is now the ONE
target and the era verdict is precision + recall per class against the
label's own base rate - no win rate, no break-even, no expectancy, no
geometry anywhere in training.
DELETED
- Expert/Excursion/ (4), Expert/BarrierHorizon/ (4), GeometrySweep,
FirstPassageLadder, Labeling/TripleBarrier.mqh (CLabelOverlap survives
in Labeling/LabelOverlap.mqh), 3 test EAs.
- TripleBarrierLabel + walk, fractal label, geometry derivation/scan/
adoption, exit-policy replay, excursion MI targets, the drift verdict
(DIRECTION_INTELLIGENT), the recall floor, balanced-accuracy telemetry,
the barrier defines, the .cfg geometry adopt (slots kept as zeros for
the positional layout), the derived-geometry live-order override.
- TRAINING_TARGET input/enum: direction models are always swing; META2
re-keys the meta head onto label agreement (descriptor loses its two
geometry slots).
REWORKED
- Labels.mqh (1795 -> ~370 lines): AdvanceSwingLabelState with
FINALITY-GATED CACHING - an unresolved bar (pivot pair uncommitted) is
never cached, so it can never freeze as a false Neutral; training,
calibration, OOS scoring and online learning all skip unresolved bars.
- SDeployVerdict: significance-only; SOosTally chance = larger
directional class share; pooled gate poolability = timeframe (record v2).
- Purge/embargo/declustering gaps: the measured mean label resolution
lag (LabelResolutionBars), not a barrier horizon.
- Pool purge key + backfill DB rows: marked at the bar the label
resolved on (m_labelResolveAge), not a fabricated barrier touch.
- Online learning frontier: finality, not a horizon delay.
- m_bestBalancedOos -> m_bestSelectionScore, m_erasSinceBestBalanced ->
m_erasSinceBest, ensemble vote outcome arrays -> label arrays.
STEP 4 folded in: Entry_Multiplier / SL_Mode / TP_Mode / tradingdirection
are inputs again - trade management is the tester GA's search space.
Fingerprints: every direction model re-keys (TGT:SWG1 now unconditional,
CUT token gone); META1 -> META2. Full retrain, as planned.
Compile-verified in _claude_stage: Warrior_EA + both surviving test EAs,
0 errors, 0 warnings each.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 20:42:31 -04:00
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.DataHiddenLayerActivation() : PRELU; }
|
refactor(topology): split shape derivation into CTopology, leave the boot sequence in place
Expert/AIBase/Topology.mqh (1191 lines) held two genuinely different jobs: the
fingerprint/derived-shape/BuildFreshTopology math, and InitNeuralNetwork/
InitFeatureIndicators - the network boot sequence (config-lock, tester-cache
seeding, load/save the .cfg, net-load backend fallback, chart/persistence/
online-learning orchestration).
Extracted the first job to Expert/Topology/ as CTopology + CTopologyView/
CAIBaseTopologyView (20 methods: BuildModelFingerprint, the Estimated*/Compute*
budget math, the Conv*/Lstm* shape helpers, Add*Stage, BuildFreshTopology).
STATELESS, like ModelPersistence - grep-verified zero exclusive fields, every
member these methods touch is shared elsewhere in the signal. Reused ~15
existing Data*/Chart*/Persist*/Exc* getters per the established convention;
added ~20 new getter overloads next to their existing setters (UseVolumes(),
MinDirectionalRecall(), etc. - same pattern as SignalClusterWindow) and ~16
new Topology*() wrappers for fields with no prior accessor. The Net-pointer
swap in BuildFreshTopology is one consolidated view call
(TopologyReplaceNetFromTopology), same doctrine as Persistence's
RunCpuInferenceSelfCheck - irreducible pointer work, not signal state.
Deliberately did NOT extract InitNeuralNetwork/InitFeatureIndicators: they
orchestrate nearly every other collaborator (chart, persistence, online-
learning, cross-asset, config-lock) rather than deriving a shape, so moving
them would just relocate a hub, not reduce coupling - same judgment call as
Inference.mqh (assessed, not extracted). They stay in the AIBase/Topology.mqh
partial, byte-identical to before (diffed against git HEAD to confirm), and
now call the extracted math through the same public forwards every other
caller already used.
Verified: string- and numeric-literal diff of the old file's 20 method bodies
against the new CTopology methods (0 differences), InitNeuralNetwork/
InitFeatureIndicators byte-identical, self-compiled 0 errors/0 warnings.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-23 23:23:00 -04:00
|
|
|
ENUM_ACTIVATION CAIBaseTopologyView::OutputLayerActivation(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.PersistOutputLayerActivation() : TANH; }
|
|
|
|
|
int CAIBaseTopologyView::NetInputWidth(void)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.TopologyNetInputWidth() : 0; }
|
|
|
|
|
bool CAIBaseTopologyView::ReplaceNetFromTopology(CArrayObj *topology)
|
|
|
|
|
{ return (CheckPointer(m_owner) != POINTER_INVALID) ? m_owner.TopologyReplaceNetFromTopology(topology) : false; }
|
|
|
|
|
void CAIBaseTopologyView::ResetOnlineLearningForFreshTopology(void)
|
|
|
|
|
{ if(CheckPointer(m_owner) != POINTER_INVALID) m_owner.TopologyResetOnlineLearningForFreshTopology(); }
|
|
|
|
|
#endif // WARRIOR_TOPOLOGY_AIBASETOPOLOGYVIEWIMPL_MQH
|
|
|
|
|
//+------------------------------------------------------------------+
|