Warrior_EA/Expert
Repository files (latest commit first)
Filename Latest commit message Latest commit date
AnimateDread 788115970c fix(vote): unranked members voted with the stock 25/50/75/100 ladder
Two defects behind "arrows drawn while members are still mid-era".

1. THE DRAW. The filtered overlay armed on the FIRST member to finish
   pass 3 and leaned on a 60 s rate limit to "collapse the burst",
   assuming members finish seconds apart. They do not - on USDJPY one
   member was at sample 10496 of pass 2 while another was at 2304,
   minutes apart. A member with no era-end snapshot returns false from
   SnapshotVoteAt, and the sweep's `if(!hasData) continue;` skips it
   BEFORE `den += ModuleWeight()`, so the one finished model's tier
   weight became the entire vote and was drawn as a consensus arrow.

   An abstention is a member that looked at the bar and said nothing; a
   missing snapshot is a member that has not looked. The first must
   dilute the vote, the second must suppress the draw. The arm is now a
   readiness MASK - one bit per m_ensembleIndex, set at that member's
   pass-3 completion, cleared when a sweep arms - and a sweep waits for
   every enrolled member. Bounded at 10 minutes so a member that stops
   cannot freeze the chart, and the partial draw PRINTS which members
   were missing: the be39674 lesson is that a hold must never silence
   the thing that reports it.

2. THE VOTE ITSELF, which is the worse half and is not display-only.
   Tier weights are not persisted in the .nnw - they exist only as the
   output of a completed pass 3 - so before a member's first
   RankTiersFromOos() it holds the constructor's stock 25/50/75/100.
   Since 4858507 the vote currency is a WIN RATE, so an unranked tier-3
   call enters the capability-weighted mean claiming a 100% win rate
   beside ranked members contributing ~25. Not a strong opinion: the
   wrong unit. One unranked member drags the ensemble over any
   threshold, on every fresh deploy and every resume. USDJPY has a
   measured ceiling of ~19 and was firing anyway.

   LiveVoteContribution() now abstains until self-ranked, which drops
   the member from the sum AND the divisor. One function, so live and
   the gate move together (2c443ba).

Era 0 will therefore report 0 coverage until each member completes one
era. The ensemble line says so explicitly rather than leaving it to look
like the USDJPY unreachable-threshold case - the two are identical in
the coverage number and completely different problems.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 08:55:04 -04:00
..
AIBase fix(vote): unranked members voted with the stock 25/50/75/100 ladder 2026-08-23 08:55:04 -04:00
ADIndicatorTuner.mqh refactor(comments): box headers to stdlib length 2026-08-22 00:30:14 -04:00
ExpertCustom.mqh refactor(comments): stdlib comment style across the remaining in-scope files 2026-08-22 00:25:52 -04:00
ExpertMoneyCustom.mqh refactor(comments): box headers to stdlib length 2026-08-22 00:30:14 -04:00
ExpertSignalAIBase.mqh fix(vote): unranked members voted with the stock 25/50/75/100 ladder 2026-08-23 08:55:04 -04:00
ExpertSignalCustom.mqh refactor(comments): box headers to stdlib length 2026-08-22 00:30:14 -04:00
README.md refactor(ai): extract Layer.mqh and deduplicate AI config 2026-08-01 11:27:28 -04:00

Expert/ Directory Documentation

Market-submission compliance (article 2555)

Every runtime check from The Checks a Trading Robot Must Pass Before Publication in the Market is implemented in System/TradeChecks.mqh (free functions, TC* prefix) and applied by the classes in this folder. Where each rule lives:

# Rule Implemented in
1 Catch/fix errors via the tester Development practice; every rejection below logs a throttled reason
2 Insufficient funds TCCheckMoneyForTrade / TCFitVolumeToFreeMargin, applied by CExpertMoneyCustom::ValidateLotForTrade
3 Invalid volumes TCCheckVolumeValue / TCNormalizeVolume, same call site
4 Pending-order count limit TCIsNewOrderAllowed, checked in CExpertSignalCustom::OpenParams and again in CExpertCustom::OpenLong/OpenShort
5 Per-symbol lot limit TCSymbolVolumeAllowed / TCApplySymbolVolumeLimit
6 SYMBOL_TRADE_STOPS_LEVEL TCCheckStops / TCAdjustStops / TCCheckPendingPrice, applied when the setup is shaped and again immediately before the order is sent
7 SYMBOL_TRADE_FREEZE_LEVEL TCFreezeOkForPosition / TCFreezeOkForOrder, gating close, reverse, trailing, order modify and order delete in CExpertCustom
8 Insufficient quote history TCHasEnoughHistory, in CExpertCustom::Refresh and CExpertSignalCustom::OpenParams
9 Array out of range TCIndexOk, plus the existing index guards (iLowest/iHighest return values, Direction()'s bounded loops)
10 Zero divide TCSafeDivide, plus explicit zero-denominator guards on every volume-step / loss division
11 Modification with no changes TCPositionModifyIsMeaningful / TCOrderModifyIsMeaningful, in the TrailingStop* / TrailingOrder* overrides
12 No DLL imports Build-time: WARRIOR_MARKET_BUILD compiles out the #import blocks in AI/NeuronDirectML.mqh
13 No external iCustom Build-time: #resource block in Warrior_EA.mq5 + WARRIOR_CI() in Variables/IndicatorResources.mqh
14 Invalid function parameters TCSymbolIsTradeable, plus the existing ValidationSettings() range checks
15 Access violation No runtime check exists by definition; the NULL-pointer and index guards above are what prevent it
16 CPU / memory consumption TCWarnIfSlow on each OnTick pass (EXPERT_TICK_BUDGET_US) and TCWarnIfMemoryAbove on each timer pass (EXPERT_MEMORY_SOFT_LIMIT_MB)

All rejections report through TCLog(), which throttles per condition so a state that persists for many ticks writes one journal line per minute instead of thousands.

Class hierarchy

CExpert          -> CExpertCustom          (event dispatch, order lifecycle, article-2555 gates)
CExpertMoney     -> CExpertMoneyCustom     (volume correction, margin fitting)
CExpertSignal    -> CExpertSignalCustom    -> CExpertSignalAIBase -> CSignalPAI/CONV/LSTM/HYBRID

ExpertCustom.mqh

Base expert. Virtual handlers for OnTick / OnTimer / OnChartEvent, trading-object setup, series refresh, and the freeze/stops-level gates applied immediately before every send, modify and delete.

ExpertMoneyCustom.mqh

  • CheckAndCorrectVolumeValue — clamps volume to the broker's min/max/step and describes each correction.
  • CheckAndAdjustMoneyForTrade — reduces lots to fit free margin rather than failing the order outright.
  • ValidateLotForTrade — the single gate for rules 2/3/5/14, with throttled logging.

ExpertSignalCustom.mqh

Shared non-AI signal machinery: database-backed signal tracking, pattern weighting, OpenParams() (which shapes SL/TP and applies the min-R:R rejection), and the filter collection. SL_Mode/TP_Mode live here — note they define the AI training target as well as the order, since the triple-barrier label is built from them.

There is no duplicate-trade detection. Three methods that implied otherwise were declared but never defined or called, and were removed in 2026-07. Do not assume the guard exists.

ExpertSignalAIBase.mqh

The AI signal base class. The declaration lives here; the method bodies are split by responsibility into Expert/AIBase/ and included at the bottom of the file, after the declaration. Include them nowhere else.

Expert/AIBase/ holds
Training.mqh era loop, plateau ladder, checkpoint selection, auto-deploy
Topology.mqh network bootstrap, derived shape, conv/LSTM/batch-norm stages
Features.mqh indicator creation, per-bar input feature vector
ChartUI.mqh arrows, arrow persistence, status panel, cleanup
Lifecycle.mqh ctor/dtor, the vote API, tick + chart-event dispatch, config lock
Persistence.mqh .stats / .cfg sidecars, CPU-inference validation
OnlineLearning.mqh live continual learning, EMA shadow, OOS simulator
Labels.mqh triple-barrier labels, async label-cache prebuild
AutoTune.mqh indicator auto-tuner
Inference.mqh softmax, prior calibration, class priors

The topology is derived, not configured — width, taper, depth, conv filters and LSTM hidden size all come from the data shape. See Topology.mqh and Variables/Inputs.mqh for which inputs were removed and why.