Warrior_EA/Variables/Variables.mqh

35 lines
2.8 KiB
MQL5
Raw Permalink Normal View History

feat(nn): derive dense depth, train on all history, pin the shape in .cfg Completes the derived-topology work. Three inputs removed. AIType loses its depth suffix - AI_MLP/AI_CONV/AI_LSTM/AI_HYBRID, five entries instead of eight. Depth is now derived from the two endpoints the taper already has to connect (derived first-layer width, output-tied final width) at a 2x per-layer compression target, clamped [2..5]. Asking a user to pick a layer count while the code derives the widths those layers taper between was asking for half a decision: at 64 units tapering to 12, four layers compress by 1.4x per step and five by 1.3x, so the extra depth bought no abstraction. On the shipping H1/10y default the derivation lands on 3 layers - the depth that actually won Run 2. StudyPeriods removed. There is no case for training on less data than the broker provides at a ~6% directional base rate; the honest generalization read comes from the OOS holdout, not from withholding history. Training now starts at the earliest available bar, floored by MinTrainYear, which answers a different question (excluding dubious pre-history) and stays. That required closing the hazard the old code documented: the capacity budget now MEASURES the symbol's real bar count, and a topology derived from a measurement would widen as history downloads. Both ends are now pinned. Every derived value left the weights-filename fingerprint - keying a filename on a measured quantity means the EA looks for a file that does not exist, starts from era 0 and orphans a trained model, silently, because a missing cache is the normal first-run state. The shape lives in the .cfg instead, where LoadAndCompare now ADOPTS the four derived fields rather than diffing them; a mismatch there would discard a fully-trained model over nothing the user did. Two fields appended to the .cfg for the conv/LSTM stages, length-guarded on read because FileReadInteger past EOF returns 0 with no error. ForceHiddenLayers, a compile-time constant like DebuggingMode, pins depth for diagnostic comparisons. It joins the fingerprint only when non-zero, so forced depths get their own files - sequential comparisons only, not simultaneous from one .ex5. Derived shape, H1/10y defaults (21 features x 20 bars): first layer 64, 3 dense, 8 conv filters, 16 LSTM units. The LSTM block halves from ~58k to ~28k weights. Both builds compile 0 errors, 0 warnings. Re-keys existing models. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 10:05:40 -04:00
//+------------------------------------------------------------------+
2025-05-30 16:35:54 +02:00
//| Warrior_EA |
//| AnimateDread |
//| |
//+------------------------------------------------------------------+
string eaName = "Warrior_EA";
fix(db): per-side pattern journaling + versioned journaling semantics The labelMatchesVote gate compared a single last-writer-wins label (LongCondition then ShortCondition) against the net vote sign, which structurally censored the pattern tables: a long event co-occurring with any short-side state model lost its label to the later writer and was dropped, while the mirrored short event journaled fine. Ichimoku models 0/3 and MA model 1 could not produce a row at all by construction (MA model 1 was "revived" in 8710240 yet still could never journal - its weight-10 vote is exactly cancelled by the opposing Pattern_0 state), and every pattern's win rate was measured on a with-trend-only subset - the exact statistic UpdateSignalsWeights() feeds back into the weights, self-sealing: no rows -> no win rate -> default weight -> still censored. - Direction() now evaluates the two ladders separately and snapshots each ladder's matched pattern into its own side slot; each side that matched journals its own row. The flat-vote poisoning the old gate fixed stays fixed: a label can no longer contradict its side. - The filter's net vote (raw pattern-weight units) is stored as a new netVote column - data, never a drop filter. Snapshot is keyed on the ladder setting a label, not on its weight, so a 0%-win-rate pattern keeps journaling and can recover. - SIGNAL_DB_SEMANTICS_VERSION is folded unconditionally into the DB filename fingerprint: pattern-definition changes (b2069bc, 8710240) re-key the database instead of blending incompatible Pattern_N populations under one key, which the input-hash fingerprint cannot see. 7 months of mixed-semantics rows shared one file because of it. - dbVersion 2.0 -> 3.0: schema changed, and inserts carry the new column, so the version-mismatch folder wipe is the migration. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 10:37:57 -04:00
//--- Version of the pattern-journaling SEMANTICS: what a row in a <Filter>_Pattern_N_<Buy|Sell> table
//--- means, which bars produce one, and what the columns are. Folded (unconditionally) into the DB
//--- filename fingerprint (ComputeDbConfigFingerprint, Warrior_EA.mq5), so bumping it re-keys every
//--- database and stale rows can never feed UpdateSignalsWeights() again. BUMP THIS whenever a signal
//--- class's pattern definitions change meaning (Signals\Signal*.mqh - e.g. b2069bc's Ichimoku models,
//--- 8710240's Sanyaku state->event), or the journaling contract in CExpertSignalCustom::Direction()
//--- changes. The config fingerprint alone cannot see code changes - it hashes inputs, and 7 months of
//--- rows recorded under three different Pattern_N meanings shared one table because nothing re-keyed.
//--- v3: per-side journaling (each side's own ladder match writes its own row; net vote is a data
//--- column, not a drop filter) + the netVote schema column.
//--- v4: a reversing signal registers its own trade after closing the opposite one (true
//--- stop-and-reverse); v3 absorbed it as an exit, which one-sided the ledger for every pure event
//--- pattern (strict alternators like MACD model 3 put all rows on whichever side fired first).
//--- v5: the OpenLongParams/OpenShortParams gate is gone from the logger - order-placement failures
//--- (stops-level, ATR warm-up, entry-mode rejection) cluster in volatility/spread conditions and
//--- were non-randomly censoring those bars out of the log. The DB logs every matched ladder,
//--- unconditionally on the decision layer.
#define SIGNAL_DB_SEMANTICS_VERSION 5
fix(db): per-side pattern journaling + versioned journaling semantics The labelMatchesVote gate compared a single last-writer-wins label (LongCondition then ShortCondition) against the net vote sign, which structurally censored the pattern tables: a long event co-occurring with any short-side state model lost its label to the later writer and was dropped, while the mirrored short event journaled fine. Ichimoku models 0/3 and MA model 1 could not produce a row at all by construction (MA model 1 was "revived" in 8710240 yet still could never journal - its weight-10 vote is exactly cancelled by the opposing Pattern_0 state), and every pattern's win rate was measured on a with-trend-only subset - the exact statistic UpdateSignalsWeights() feeds back into the weights, self-sealing: no rows -> no win rate -> default weight -> still censored. - Direction() now evaluates the two ladders separately and snapshots each ladder's matched pattern into its own side slot; each side that matched journals its own row. The flat-vote poisoning the old gate fixed stays fixed: a label can no longer contradict its side. - The filter's net vote (raw pattern-weight units) is stored as a new netVote column - data, never a drop filter. Snapshot is keyed on the ladder setting a label, not on its weight, so a 0%-win-rate pattern keeps journaling and can recover. - SIGNAL_DB_SEMANTICS_VERSION is folded unconditionally into the DB filename fingerprint: pattern-definition changes (b2069bc, 8710240) re-key the database instead of blending incompatible Pattern_N populations under one key, which the input-hash fingerprint cannot see. 7 months of mixed-semantics rows shared one file because of it. - dbVersion 2.0 -> 3.0: schema changed, and inserts carry the new column, so the version-mismatch folder wipe is the migration. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 10:37:57 -04:00
string tableschema = "year INTEGER, month INTEGER, day INTEGER, dayOfWeek INTEGER, hour INTEGER, minutes INTEGER, pattern STRING, direction STRING, entryPrice DOUBLE, exitPrice DOUBLE, result STRING, netVote DOUBLE";
2025-05-30 16:35:54 +02:00
bool IsBacktesting = false;
refactor(inputs): 96 -> 70 inputs; remove two untested/unusable filter modules Every removal below is FINGERPRINT-NEUTRAL by construction: each retired input is pinned to the exact value it already shipped with, so running models keep their filenames and resume rather than restarting at era 0. Verified field by field against BuildConfigFingerprint. Removed as inputs, kept as pinned constants (the value was never a preference the user had a basis to change): - OutputNeuronsCount. The regression head predicts a continuous quantity the triple-barrier label does not contain; the target is an EVENT, so the right output is its probability. The regression code paths stay implemented and dormant - they cost nothing and removing them would touch every scoring path at once. - MinRecall. A safety floor, not a preference, and the only direction a user can move it is the harmful one: raising it past what the config reaches yields NO model, not a better one (observed repeatedly at 60). - SwingConfirmationBars. Stopped gating the labels with the relabel, but is STILL load-bearing for the swing-context input features - it is the ZigZag repainting embargo, and without it those 9 features read a leg the live bar could not have had yet. Pinned, not deleted. - MaxErasPerRun (runaway backstop, never reached in a healthy run), FreezePriorCalibration (unanswerable by a user; near-balanced labels make the priors stable anyway), VerboseMode (developer view, joins DebuggingMode), MACD/Ichimoku periods x6 (both indicators ship disabled, and as optimizer dimensions they are pure overfitting surface - the AI auto-tuner is the supported way to move them). - SignalClusterWindow -> 3, no longer an input. Barrier labels make consecutive setups real, which argued for 0; it is not 0 because on D1+ a 6-bar window spans over a week and two arrows a day apart on a weekly-scale move are one event. 3 splits it correctly by timeframe. - EnableOnlineLearning -> ON. Adapting to a changing market is what keeps a months-attached model from going stale, and the rolling-accuracy freeze is what makes it safe. See the caveat noted in the handoff: it had not been forward-tested on a live feed when this became default. Removed entirely: - Intraday Time Filter (5 inputs + Signals/SignalITF.mqh). Two of its five inputs were raw BITMASKS, which is an implementation detail exposed as a control. The job is covered three times over by things that are declarative or that learn: the session filter, the time-of-day/day-of-week input features (the network discovers which hours are good rather than being told), and the journal's time buckets. - Market Depth Filter (5 inputs + Signals/SignalMarketDepth.mqh, plus its OnInit probe and OnDeinit release). It needs real level-2 data that this broker - and most retail MT5 brokers - do not provide, so the module has never once executed against real data. Shipping four tuning dropdowns for an untested path is worse than shipping nothing: the only users who could enable it would be its first-ever testers, live. If DOM returns it should be a FEATURE fed to the network, not a rule-based veto with hand-tuned thresholds - imbalance is data. - IndicatorTuneTrials, replaced by ComputeTuneTrialBudget(). The useful budget depends on how many parameters are actually being searched, which depends on which features are enabled - so one number meant wildly different things run to run. The shipped 32 was ~10 candidates per dimension against one enabled indicator (wasteful: each costs GA_SEEDS full training runs) and under one per dimension against all nine (blind). Now population ~ 4 x active dimensions, clamped [8,64], with CADIndicatorTuner::ActiveDimensions() defined immediately above PerturbRandom() so the two cannot drift apart. - Six orphaned enums (TUNE_TRIALS_PRESET, DOM_*, ENTRY_HOUR_OF_DAY, TIME_FILTER_DAY_OF_WEEK), 81 lines. Other UX: - SL_ATR_x1 / TP_ATR_x3 now carry the "(classic)" default marker every other preset enum in the file already used. Nothing in the SL/TP dropdowns previously told a user which pair was the shipped default - which matters far more since the relabel, because those two define the labels and changing either forces a retrain. - Neural Network section moved directly ABOVE AI Input Features: choose the architecture, then choose what it sees. NN Optimizer / Performance stays last - the Adam/Sgd inputs are declared in AI/Network.mqh and render immediately after that divider. - News feature + window moved to the end of the AI feature list, below Wyckoff Bar Inversion. - Dropped "(0-100)" from Min vote to open - it is an enum, not a number. Both builds compile 0 errors / 0 warnings. No retrain forced. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 21:22:02 -04:00
//--- EnableSessionFilter/EnableNewsFilter/EnableRiskGuard are real inputs (Variables\Inputs.mqh),
//--- consistent with every other filter's on/off toggle. EnableITF and EnableMarketDepth are gone -
//--- both modules were removed 2026-08-01, see the removal notes in that file.
feat(nn): derive dense depth, train on all history, pin the shape in .cfg Completes the derived-topology work. Three inputs removed. AIType loses its depth suffix - AI_MLP/AI_CONV/AI_LSTM/AI_HYBRID, five entries instead of eight. Depth is now derived from the two endpoints the taper already has to connect (derived first-layer width, output-tied final width) at a 2x per-layer compression target, clamped [2..5]. Asking a user to pick a layer count while the code derives the widths those layers taper between was asking for half a decision: at 64 units tapering to 12, four layers compress by 1.4x per step and five by 1.3x, so the extra depth bought no abstraction. On the shipping H1/10y default the derivation lands on 3 layers - the depth that actually won Run 2. StudyPeriods removed. There is no case for training on less data than the broker provides at a ~6% directional base rate; the honest generalization read comes from the OOS holdout, not from withholding history. Training now starts at the earliest available bar, floored by MinTrainYear, which answers a different question (excluding dubious pre-history) and stays. That required closing the hazard the old code documented: the capacity budget now MEASURES the symbol's real bar count, and a topology derived from a measurement would widen as history downloads. Both ends are now pinned. Every derived value left the weights-filename fingerprint - keying a filename on a measured quantity means the EA looks for a file that does not exist, starts from era 0 and orphans a trained model, silently, because a missing cache is the normal first-run state. The shape lives in the .cfg instead, where LoadAndCompare now ADOPTS the four derived fields rather than diffing them; a mismatch there would discard a fully-trained model over nothing the user did. Two fields appended to the .cfg for the conv/LSTM stages, length-guarded on read because FileReadInteger past EOF returns 0 with no error. ForceHiddenLayers, a compile-time constant like DebuggingMode, pins depth for diagnostic comparisons. It joins the fingerprint only when non-zero, so forced depths get their own files - sequential comparisons only, not simultaneous from one .ex5. Derived shape, H1/10y defaults (21 features x 20 bars): first layer 64, 3 dense, 8 conv filters, 16 LSTM units. The LSTM block halves from ~58k to ~28k weights. Both builds compile 0 errors, 0 warnings. Re-keys existing models. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 10:05:40 -04:00
bool EnablePAI = (AIType == AI_MLP);
bool EnableCONV = (AIType == AI_CONV);
bool EnableLSTM = (AIType == AI_LSTM);
bool EnableHYBRID = (AIType == AI_HYBRID);
feat: S2 meta-labeling head - binary trade-quality model over the classic-candidate corpus The NN now has a target that is not per-bar direction (closed, best-of-999 p=1.0000): P(win | this journaled candidate, at the EA's own SL/TP, net of cost). One net for all 52 pattern-sides, AIType=AI_META. - NetForward.mqh: the host-side softmax+CE gradient generalized total==3 -> 2||3 on both backprop paths; a 2-class softmax IS a logistic head, and no compute backend changes. - SignalMETA.mqh (new): corpus loaded read-only from the LARGEST signal DB on disk (decoupled from the config fingerprint that burned four S1 runs); the GMT->server offset is measured PER ROW against entryPrice vs bar open (DST-immune, histogram logged); a window-span regime filter drops the pre-2017 daily-backfill rows; 31-feature setup descriptor appended at the input (26 one-hot + side + tanh netVote + SL/TP ATR + spread/ATR). - Training.mqh: candidate-queued pass 1, binary-target pass 2, per-candidate calibration (2.5) and OOS (3) walks. Counter mapping win->Buy / loss->Sell lets checkpoint selection, the edge floor, the plateau ladder and the family-wise deploy gate run UNCHANGED: precision reads as win rate among traded candidates, chance as the base win rate, recalls as sensitivity/ specificity. Era-end META line: coverage x (p - break-even) vs the null. - Labels are the side-conditional triple-barrier win caches - never the DB's stop-and-reverse outcome. Logit adjustment deliberately skipped (~40% base rate). Live inference + online learning guarded off until S3. - Fingerprint: conditional |TGT:META1; State\META\ folder + 2-output filename slot keep meta models fully separate from direction models. Compiles clean (0 errors, 0 warnings). S2 run = attach a chart with AIType=AI_META; S3 wires the votes via the per-side hooks. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 06:52:31 -04:00
bool EnableMETA = (AIType == AI_META);
2025-05-30 16:35:54 +02:00
//+------------------------------------------------------------------+