Warrior_EA/Signals/SignalHYBRID.mqh

67 lines
3.9 KiB
MQL5
Raw Permalink Normal View History

fix(ai): drop the conv pooling stage - it reduced across filters, not time FeedForwardConv emits POSITION-MAJOR output, matrix_o[out + window_out * i], so one bar's window_out filter responses are contiguous and consecutive bars sit window_out apart. Both pooling implementations (FeedForwardProof and CPU_FeedForwardProof) slide FLAT over that buffer - pos = i * step, reducing `window` CONSECUTIVE elements. On a position-major layout those neighbours are different FILTERS of the same bar, never one filter across time. At the shipped 3/2 the pool computed max(bar0_f0, bar0_f1, bar0_f2), then max(bar0_f2, bar0_f3, bar0_f4), with every 8th window straddling a bar boundary. So it collapsed unrelated feature detectors into whichever fired hardest, passed gradient to that winner only, and halved the feature map while doing it - all below every learnable layer, where nothing above can recover it. The removed inputs' own labels ("3 Bars") show time-axis pooling was the intent throughout. Measured cost: CONV sat pinned at ~40% balanced accuracy for 510 eras with Sell recall 0%, while plain MLPs on the same data reached 57-61%. HYBRID, which also carried this stage, came second-worst of the batch-norm group. Not fixable in the topology: pooling one filter across time needs a stride of window_out BETWEEN samples within a window, which a consecutive-window kernel cannot express at any window/step. That needs a stride-aware kernel in Network.cl + WarriorCPU.cpp + WarriorDML.cpp and a DLL rebuild, and is only worth doing if a conv front-end earns its place without downsampling first - with 20 sliding positions there is little to gain by halving them. ConvPoolWindow/ConvPoolStep and their enums are removed with it, along with the |CP: fingerprint term added earlier today. Both builds compile 0 errors, 0 warnings. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 19:28:44 -04:00
//+------------------------------------------------------------------+
//| Warrior_EA |
//| AnimateDread |
//| |
//+------------------------------------------------------------------+
#include "..\Expert\ExpertSignalAIBase.mqh"
// wizard description start
//+------------------------------------------------------------------+
//| Description of the class |
//| Title=Signals of indicator 'CNN-LSTM AI' |
//| Type=SignalAdvanced |
//| Name=CNN-LSTM AI |
//| ShortName=HYB |
//| Class=CSignalHYBRID |
//| Page=signal_hybrid |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| Class CSignalHYBRID. |
//| Purpose: a single fused CNN-LSTM signal that stacks Conv+Pool |
//| layers before the LSTM layer, then the shared dense taper. |
//| The base AI voting path still applies, so this module trades as |
//| one coherent signal instead of three loosely synchronized ones. |
//+------------------------------------------------------------------+
class CSignalHYBRID : public CExpertSignalAIBase
{
protected:
virtual bool AddCustomLayers(CArrayObj *topology) override;
//--- AddCustomLayers below appends BOTH stages, conv first - so this topology's LSTM is fed the conv
//--- feature map rather than the raw input. Keep these in step with AddCustomLayers: they are what let
//--- the capacity budget size the recurrent block against its REAL fan-in (see LstmFanIn()).
virtual bool UsesConvStage(void) const override { return true; }
virtual bool UsesLstmStage(void) const override { return true; }
virtual ENUM_ACTIVATION HiddenLayerActivation(void) override { return TANH; }
public:
CSignalHYBRID(void);
virtual bool InitIndicators(CIndicators *indicators) override;
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CSignalHYBRID::CSignalHYBRID(void)
{
fix(ensemble): per-member arrow namespaces; ConvLSTM rename; dialog in purge list The ensemble chart UI had a shared-namespace defect that answered the user question "what do the arrows represent?" with "a bug": all four members drew arrows under the same WarSig_<bartime> object names, so the chart showed whichever member rendered LAST, one member Neutral deleted another member Buy at the same bar, each member init sweep wiped the arrows the previous member had just restored, and SaveChartSignals - which rebuilds the sidecar by SCANNING the chart - persisted every other member arrows into its own history (the exact cross-model laundering its own header warns about, now happening BETWEEN ensemble members). Arrows are now namespaced per member (WarSig_PAI_, WarSig_CONV_, WarSig_LSTM_, WarSig_HYB_): draw, delete, restore, prune, member init sweep, destructor purge and the sidecar scan are all member-scoped, and the tooltip names the model. Global purges keep matching the bare WarSig_ prefix, which covers all member namespaces plus old-format leftovers from earlier builds. Labels: the ensemble panel header no longer says "HYBRID ensemble" (HYBRID is one member; the header is the ensemble) and the CONVLSTM member displays as ConvLSTM instead of Hybrid. Its SHORT id stays HYB deliberately - it names the model folder and changing it would orphan every model trained under that path. Deinit: the alt-data mapping dialog namespace (WarriorAltMap_) joins WarriorChartPrefixes, so both the OnInit purge and the deinit final sweep now cover it - it was in neither list, so a dialog starved of its own Destroy() left its controls on the chart permanently. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 18:26:55 -04:00
//--- Display name follows the 2026-08-15 rename (AI_CONVLSTM: conv front-end + LSTM).
//--- The SHORT id stays "HYB" deliberately: it names the model folder
//--- (Neural Networks\State\HYB\) and changing it would orphan every model trained
//--- under the old path - a rename is not worth a forced retrain.
SetIdentity("ConvLSTM", "HYB");
}
//+------------------------------------------------------------------+
//| Create indicators and bootstrap/load the network. |
//+------------------------------------------------------------------+
bool CSignalHYBRID::InitIndicators(CIndicators *indicators)
{
return InitNeuralNetwork(indicators);
}
//+------------------------------------------------------------------+
//| Conv + Pool front-end followed by an LSTM sequence layer. This |
//| matches the standalone CONV front-end exactly, then adds LSTM. |
//+------------------------------------------------------------------+
bool CSignalHYBRID::AddCustomLayers(CArrayObj *topology)
{
refactor: compose topologies from named stages; drop dead code DRY - topology construction --------------------------- CSignalCONV and CSignalHYBRID each built the Conv+Pool front-end from scratch; CSignalLSTM and CSignalHYBRID each built the LSTM stage from scratch. The duplicates had already drifted: HYBRID guarded the LSTM step with MathMax(1, historyBars/2), CSignalLSTM divided unguarded, so a historyBars of 1 gave two different steps for what is documented as the same layer. Extracted AddConvPoolStage() and AddLstmStage() onto CExpertSignalAIBase. The three overrides are now compositions: CONV = AddConvPoolStage LSTM = AddLstmStage HYBRID = AddConvPoolStage && AddLstmStage HYBRID's "matches the standalone CONV front-end exactly, then adds LSTM" is enforced by construction instead of by comment. Took the guarded step for both. Also fixed a descriptor leak the duplicates shared: on a failed topology.Add() the CLayerDescription was neither owned by the array nor deleted. Dead code --------- - CNet::SaveCheckpoint / CNet::LoadCheckpoint (123 lines). Superseded by the in-memory CaptureWeights/RestoreWeights pair; Network.mqh:1312 already said so ("This replaces the file-based SaveCheckpoint/LoadCheckpoint"). Zero call sites - every remaining mention was a comment. The five comments that referenced them have been reworded rather than left dangling. - CExpertSignalCustom::CheckForDuplicateTrade / FindLastTradeIndex / UpdateTradeStatusAndExit: declared, never defined anywhere, never called. They only made it look as though duplicate-trade detection existed. Compiles 0 errors, 0 warnings. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 00:38:05 -04:00
//--- "the standalone CONV front-end exactly, then adds LSTM" is now enforced by construction:
//--- both stages are the same code CSignalCONV and CSignalLSTM run.
fix(ai): drop the conv pooling stage - it reduced across filters, not time FeedForwardConv emits POSITION-MAJOR output, matrix_o[out + window_out * i], so one bar's window_out filter responses are contiguous and consecutive bars sit window_out apart. Both pooling implementations (FeedForwardProof and CPU_FeedForwardProof) slide FLAT over that buffer - pos = i * step, reducing `window` CONSECUTIVE elements. On a position-major layout those neighbours are different FILTERS of the same bar, never one filter across time. At the shipped 3/2 the pool computed max(bar0_f0, bar0_f1, bar0_f2), then max(bar0_f2, bar0_f3, bar0_f4), with every 8th window straddling a bar boundary. So it collapsed unrelated feature detectors into whichever fired hardest, passed gradient to that winner only, and halved the feature map while doing it - all below every learnable layer, where nothing above can recover it. The removed inputs' own labels ("3 Bars") show time-axis pooling was the intent throughout. Measured cost: CONV sat pinned at ~40% balanced accuracy for 510 eras with Sell recall 0%, while plain MLPs on the same data reached 57-61%. HYBRID, which also carried this stage, came second-worst of the batch-norm group. Not fixable in the topology: pooling one filter across time needs a stride of window_out BETWEEN samples within a window, which a consecutive-window kernel cannot express at any window/step. That needs a stride-aware kernel in Network.cl + WarriorCPU.cpp + WarriorDML.cpp and a DLL rebuild, and is only worth doing if a conv front-end earns its place without downsampling first - with 20 sliding positions there is little to gain by halving them. ConvPoolWindow/ConvPoolStep and their enums are removed with it, along with the |CP: fingerprint term added earlier today. Both builds compile 0 errors, 0 warnings. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 19:28:44 -04:00
return AddConvStage(topology) && AddLstmStage(topology);
}
//+------------------------------------------------------------------+