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 |
|
|
|
|
|
//| |
|
|
|
|
|
//| The read/write surface CTopology needs from the signal. Same |
|
|
|
|
|
//| shape as Persistence\IPersistenceView.mqh - abstract, pure `= 0`,|
|
|
|
|
|
//| no signal include. Everything here is either a fingerprint input,|
|
|
|
|
|
//| a size the shape derivation reads, or the two irreducible |
|
|
|
|
|
//| pointer operations (the Net swap, the online-learning reset) |
|
|
|
|
|
//| that are not signal STATE and so are consolidated into one call |
|
|
|
|
|
//| each rather than exposed field-by-field. |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
class CTopologyView
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
virtual ~CTopologyView(void) { }
|
|
|
|
|
//--- IDENTITY + SIZE (reused via the signal's existing Data*()/Chart*() getters)
|
|
|
|
|
virtual string Id(void) = 0;
|
|
|
|
|
virtual string SymbolName(void) = 0;
|
|
|
|
|
virtual ENUM_TIMEFRAMES Timeframe(void) = 0;
|
|
|
|
|
virtual int OptimizationAlgo(void) = 0;
|
|
|
|
|
virtual int OutputNeuronsCount(void) = 0;
|
|
|
|
|
virtual int NeuronsCount(void) = 0;
|
|
|
|
|
virtual int HistoryBars(void) = 0;
|
|
|
|
|
virtual int InitialNeuronsCount(void) = 0;
|
|
|
|
|
virtual int HiddenLayersCount(void) = 0;
|
|
|
|
|
virtual int ConvFilterCount(void) = 0;
|
|
|
|
|
virtual int LstmHiddenSize(void) = 0;
|
|
|
|
|
virtual int MinTrainYear(void) = 0;
|
|
|
|
|
virtual int FractalPeriods(void) = 0;
|
|
|
|
|
virtual int OosSplitPct(void) = 0;
|
|
|
|
|
virtual int SwingConfirmationBars(void) = 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
|
|
|
//--- The LABEL'S pivot source, read at init to measure the swing geometry the window and the
|
|
|
|
|
//--- capacity budget are both derived from - see CTopology::MeasureSwingGeometry().
|
|
|
|
|
virtual int ZigZagHandle(void) = 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
|
|
|
//--- FINGERPRINT INPUT FLAGS (BuildModelFingerprint) - every one already has a signal-side setter;
|
|
|
|
|
//--- these are the matching getters.
|
|
|
|
|
virtual bool UseVolumes(void) = 0;
|
|
|
|
|
virtual bool UseTime(void) = 0;
|
|
|
|
|
virtual bool UseATR(void) = 0;
|
|
|
|
|
virtual bool UseSwingContext(void) = 0;
|
|
|
|
|
virtual bool UseNews(void) = 0;
|
|
|
|
|
virtual int NewsFeatureWindowMinutes(void) = 0;
|
|
|
|
|
virtual bool UseMA(void) = 0;
|
|
|
|
|
virtual bool UseCrossAsset(void) = 0;
|
|
|
|
|
virtual bool UseSpreadFeature(void) = 0;
|
|
|
|
|
//--- The DERIVED alt-data flag (InitFeatureIndicators sets it once width is known) - NOT the
|
|
|
|
|
//--- operator opt-in switch (UseAltData(bool) already means that elsewhere).
|
|
|
|
|
virtual bool UseAltData(void) = 0;
|
|
|
|
|
virtual bool IsEnsembleMember(void) = 0;
|
2026-08-25 22:51:50 -04:00
|
|
|
//--- Extra independent observations available from Training\TrainingPool.mqh, already discounted
|
|
|
|
|
//--- for cross-instrument correlation - see CTopology::EstimatedInSampleBars()'s use of it. 0 when
|
|
|
|
|
//--- pooling is off or no compatible peer file exists yet.
|
|
|
|
|
virtual double PooledIndependentBars(void) = 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
|
|
|
//--- SHAPE SEAMS - subclass-overridden virtuals on the signal (CSignalCONV/LSTM/HYBRID/META).
|
|
|
|
|
virtual bool UsesConvStage(void) = 0;
|
|
|
|
|
virtual bool UsesLstmStage(void) = 0;
|
|
|
|
|
virtual bool HasConvBeforeLstm(void) = 0;
|
|
|
|
|
virtual bool AddCustomLayers(CArrayObj *topology) = 0;
|
|
|
|
|
virtual ENUM_ACTIVATION HiddenLayerActivation(void) = 0;
|
|
|
|
|
virtual ENUM_ACTIVATION OutputLayerActivation(void) = 0;
|
|
|
|
|
virtual int NetInputWidth(void) = 0;
|
|
|
|
|
//--- IRREDUCIBLE POINTER WORK, consolidated - same doctrine as Persistence's
|
|
|
|
|
//--- RunCpuInferenceSelfCheck/ChartScoreBarForRescan: not signal state, a whole-object operation.
|
|
|
|
|
virtual bool ReplaceNetFromTopology(CArrayObj *topology) = 0;
|
|
|
|
|
//--- A fresh topology invalidates the shadow net and the online-learning history - see
|
|
|
|
|
//--- COnlineLearning::ResetForFreshTopology()'s comment.
|
|
|
|
|
virtual void ResetOnlineLearningForFreshTopology(void) = 0;
|
|
|
|
|
};
|
|
|
|
|
//+------------------------------------------------------------------+
|