- Replaced standard library signal modules with custom implementations to allow for named patterns and improved voting.
- Added new input parameters for module weights, allowing for optimization of individual signal contributions.
- Enhanced the management of trades with new options for breakeven and management cut.
- Introduced a mechanism for dynamic ranking of signal weights based on historical performance.
- Improved initialization logic to ensure proper registration of filters and handling of trading conditions.
- Added detailed logging for trading permissions and account status during initialization.
Operator: "meta labeling should drastically change the outcome anyways.
unless the journal logs every patterns independently (I think it should
and also voted trades outcomes for comparison)."
Until now the journal recorded POSITIONS - what the agreement gate let
through - so a meta-labeller would have learned from a few dozen trades
per setup. Every arming is now a virtual trade: a pending order at the
setup's own entry and stop, filled when price reaches it inside the
setup's own window, tracked through the same first-passage ladder as a
real position (one shared AdvanceTrack), closed at the ladder's last
horizon, written to the same table as filterID="Virtual:<setup>". The
parent annotates each bar's firings with agree=N, opposed and the armed
combination. Real trades stay filterID="Book", so the two populations
sit on one table. Closed virtual rows are written 200 per commit.
Context now also carries headroom, minutes to the forced close and the
order type. The `journal` global lives in the header so setups and the
signal base reach the one instance the expert feeds.
Also: SQL identifiers are quoted - "2WD_Pattern_0_Sell" starts with a
digit and every Second Wind pattern table failed to create the moment
the database was on in the tester; an index on the natural key so the
replace-on-key scales to a decade of firings; "no closed trades yet" is
verbose again.
Smoke, BTCUSD H1 one month: 52 firings, 26 filled, 26 rows, annotated,
no database errors.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Operator: "is there not a meta labeling neural network in the EA? why
did it keep taking a losing pattern? The journal is there for that."
There is no meta-label net (CNNFilter is a loader nobody instantiates;
the offline net was never built), the adaptive layer learns management
only by design, and it could not read anyway: SignalDatabaseActive()
switched the DB off for every tester run on the argument that "a tester
run's DB is written and never read" - a premise AdaptiveExitWriter had
already deleted. Every run ended with 93 verbose-level "journal read
failed - database not initialized" lines and learned nothing.
- The DB is ON in a single tester pass; optimisation and forward stay
off (12 agents on one FILE_COMMON SQLite file finished zero passes).
- A closed trade REPLACES its own row on the natural key (symbol, open
minute, side, entry price): tester tickets restart at 1 on every run,
so a re-run over the same history no longer double-counts.
- AdaptiveExitWriter writes skip_long / skip_short when a setup-side is
a categorical loser on this chart: n >= 60 and t <= -2.5 on realised
R x risk in bp, gross of commission. Not ranking - the measurement
that made selection anti-predictive ranked marginal cells against
each other; this is the shape Second Wind showed on forex (t -4.0).
A skipped side never arms, so it never counts toward agreement.
- The reader adopts the flags with the exit, once per server day, and
prints the verdict when it changes.
- "Could not read" is printed once at normal level with the reason.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
THE VOTER FIX, found in the strategy tester and worth stating plainly because it
will bite the next standalone setup too. CExpertSignalCustom weights each child
by VoteCapableWeight(), which is m_weight only when GetPatternCount() > 0 and
ZERO otherwise: a child with no patterns is a news/session-style VETO with no say
in the consensus. CSignalInsideBarGap declared none, so its first tester run
fired 192 times over 2019-2022 and placed nothing - it voted 100 with a capable
weight of 0 and the accumulator divided by zero into 0.00 on every bar. It now
carries one pattern at weight 100, an ID, and its used-series mask, exactly as
every classic module's constructor does. Tester validation of the fixed build is
in progress; this commit is compile-verified only (0 errors, 0 warnings, in a
scratch copy inside the MQL5 tree - the repo path cannot resolve Network.cl).
THE JOURNAL. Two TEXT columns, added IN PLACE with ALTER TABLE (new
EnsureColumn on the database managers) rather than a dbVersion bump, which wipes
the directory:
context key=value;... the setup's view at signal time, the same terms the
research conditioned on, named identically (PublishContext). Accepted
by the journal only when published within 180 s of the position
opening, so an expired order's line cannot be inherited by a later
position from another signal.
passages first-touch MINUTE of every stop and target level on the research
grid plus signed R at each time-stop horizon - the exact fields
research/pricing.py prices an exit from. A synthetic round-trip
proved the live format re-prices the traded exit identically to the
research (max |diff| 4e-7 R) once the horizons carry six decimals.
One honest limit is written into the file header: a live trade is closed by its
own barriers, so from live rows an exit can only be re-selected TIGHTER.
THE ADAPTIVE EXIT. CSignalInsideBarGap reads
Common\Files\Warrior_EA\Adapt\{SYMBOL}_{PERIOD}_inside_bar_u.cfg once per server
day, written by research/journal_adapt.py with the research's discipline (choose
on the older trades, confirm on the newer, placeable stop, stable after dropping
the best 5%). No file means the validated defaults; a file outside the research
grid is refused and logged.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
ReadStoredDbVersion() already retries the FileOpen 5x with a 1s sleep
internally (OpenVersionFileWithRetry, b8f936f) before returning the
"ERROR" sentinel. Init()'s outer while(attempts<5){Sleep;retry} wrapped
that whole sequence again, so sustained lock contention could block
OnInit for ~25-30s across two stacked retry loops that read as one.
Treat a single exhausted ERROR as a hard Init() failure instead.
The warning lived inside the VerboseMode-gated corpus report, so a
forgotten wipe silently voided an entire 18-year corpus run - the
outdated-row guard rejected the whole replay against leftover rows
and the run appended 35 rows instead of building a corpus. The check
now runs unconditionally at tester OnInit (MetaCorpusStaleCheck): 52
quiet one-row newest-key probes vs the test start, with a loud stop-
wipe-rerun instruction when the DB is newer than the test. Absent
tables probe quietly via FetchNewestTimeKey''s new quiet flag.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
6819bb4 called dbm.FetchRecordCount() from ProcessSignal, but the
method only existed on CDatabaseOperationsManager - CDatabaseManager
never exposed it (nothing outside the DB layer had needed it before).
The 12 compile errors were the usual MQL cascade from one unknown
member.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The historical 1000-row cap existed for a real reason: ProcessSignal
pulled BOTH full tables into MQL struct arrays on every buffered
signal, and UpdateSignalsWeights pulled all 52 per cycle -
materializing thousands of string-bearing structs per event is the
practical limit the cap protected against (SQLite itself has none).
Raising the cap for an 18-year meta-label corpus build would have
made runs crawl; sharding across databases would re-read the same
rows and inherit the same cost.
Every question is now answered inside SQLite, one row or one number
per query, flat in table size:
- FetchOpenTradeEntry: the open (NA) trade''s entryPrice for
pattern+direction, LIMIT 1
- FetchNewestTimeKey: newest row''s yyyymmddhhmm via max ROWID
(rows insert chronologically) - the duplicate/outdated guard
- FetchWinLossCounts: COALESCE''d SUM aggregates with the
before-now bound applied in SQL, replacing the tester-only array
trim (now also active live, where it is harmless by construction)
ProcessSignal semantics preserved exactly: prune -> close opposite
(stop-and-reverse still registers its own row) -> duplicate/outdated
-> one-open-trade -> register. CalculatePatternWinRate''s array walk
becomes WinRateFromCounts; the private FetchTradeRecords wrapper and
ShouldDeleteOldestEntry are gone. DB_MaxRowsPerTable=20000 is now
cheap at any table size.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Added optional `weighScale` parameter (default -1.0) to `CNeuronBase::Init` and `CLayer::CreateElement`.
- Updated `CNeuronPool::Init` to use LeCun-uniform scaling (1/sqrt(window+1)) for its base initialization.
- Updated `CNet::CNet` to use He-scaled initialization (sqrt(2/neurons)) for dense layers.
- These changes enable more flexible and statistically sound weight initialization, matching the rationale used in OCL-based implementations, leading to better training stability and convergence.
- Define MAX_WEIGHT constant (1.0e6) for weight limits in clusters
- Remove redundant barrier from FeedForward kernel (prevents sync issues)
- Port FeedForwardProof and CalcInputGradientProof kernels for max-pooling (no weights, sliding max)
- Port FeedForwardConv kernel for convolution layers (shared weights, multiple output channels)
- Remove unused code and refactor signal condition logic (CSignalPAI)