Warrior_EA/Variables/ConfidenceBridge.mqh
AnimateDread 15827a6b77 refactor(trade-mgmt): remove all confidence-scaled trade management
Five modes went, all of them staking real risk on the model's confidence:
Intelligent entry (ENTRY_INTELLIGENT), stop (SL_INTELLIGENT), target
(TP_INTELLIGENT), trailing (CTrailingIntelligent) and lot size
(CMoneyIntelligent's quarter-Kelly). With them, the Confidence_Source
input and the CONFIDENCE_SOURCE enum, whose only job was choosing which
number those five read.

The reason is calibration, not correctness: the confidence magnitude is
known to be miscalibrated against the label prior, so every one of these
modes multiplied money by a quantity whose units were never established.
The DB arm had a second, independent defect - since the tester DB guard
(SignalDatabaseActive) it reads 0 in tester and optimizer but non-zero
live, so any backtest of CONF_DB/CONF_BLENDED could not reproduce live
trading. And what the DB produces is a filter-RANKING win rate, not a
per-trade win probability.

Both confidence numbers are still recorded per trade (aiConfidence /
dbConfidence) and still bucketed against outcome in TradeJournalReport.
Recording is what keeps the question answerable; acting on it was the
part with no evidence behind it. ConfidenceBridge.mqh now carries an
explicit telemetry-only rule at the top.

ENUM ORDINALS PINNED. Removing a member vacated a value in four enums at
once and MT5 does not validate an enum input replayed from a saved .set
or a stored optimization pass. TRAILING_STRATEGY and
MONEY_MANAGEMENT_STRATEGY now carry explicit values so the survivors keep
the numbers they were saved as, and ValidateBarrierInputs is widened into
ValidateTradeManagementInputs covering SL_Mode, TP_Mode,
Entry_Multiplier, TrailingStrategy and MM_STRATEGY. Without that gate a
chart saved with the Intelligent stop would feed SL_Mode = -1 into a
multiplier now used verbatim, placing the stop on the wrong side of entry.

RETRAIN-NEUTRAL: neither SL_Mode nor TP_Mode appears in
BuildModelFingerprint() or ComputeDbConfigFingerprint() since the
swing-pivot target replaced the barrier labels. No .nnw, .cfg or .db
re-keys. Also drops the now-dead g_TradeRewardRiskRatio bridge, the
CMoneyRiskBase::AdjustRiskAmount hook and the unsigned AIConfidence().

Compile-verified in _claude_stage: 0 errors, 0 warnings.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-25 10:10:20 -04:00

76 righe
5 KiB
MQL5

//+------------------------------------------------------------------+
//| Warrior_EA |
//| AnimateDread |
//| |
//+------------------------------------------------------------------+
//--- TELEMETRY ONLY SINCE 2026-08-25 - NOTHING HERE MAY STEER A TRADE.
//---
//--- These globals used to be a control path: OpenParams() refreshed them, and the five "Intelligent"
//--- trade-management modes (entry / SL / TP / trailing / lot size) read them back to size real risk.
//--- All five are gone, and the reason is worth keeping next to the numbers themselves: the model's
//--- confidence is KNOWN TO BE MISCALIBRATED (it over-calls by roughly an order of magnitude against
//--- the label prior), so every one of those modes was scaling money by a quantity whose units were
//--- never established. Uncalibrated is not the same as uninformative - it may well rank trades
//--- correctly even while its absolute level is meaningless - which is exactly why the numbers are
//--- still RECORDED here and journalled per trade (aiConfidence / dbConfidence in
//--- Database\TradeJournalManager.mqh, bucketed against realised outcome in TradeJournalReport.mqh).
//--- That report is the evidence a future confidence-scaled mode would have to produce first.
//---
//--- THE RULE: a write to any global in this file must be observable only in the journal, the panel,
//--- or a log line. If a new reader would change an order's price, size, stop or lifetime, it does
//--- not belong here - it belongs behind a measurement.
double g_AISignedConfidence = 0.0; // -1..1, sign = direction, magnitude = AI confidence; 0 if no AI filter
double g_DBConfidence = 0.0; // 0..1, historical time-based win rate of the active pattern set
// Live per-tick signed AI confidence (-1..1, sign = predicted direction, magnitude = confidence),
// refreshed every tick/timer from the active AI signal's SignedAIConfidence() in
// CExpertSignalAIBase::ScheduleTrainingIfNeeded(). Kept because it is the only read available while a
// position is already OPEN (an open position generates no further OpenParams() calls), which is the
// interesting half of any future confidence-vs-outcome study - does conviction decay before the loss?
double g_LiveAISignedConfidence = 0.0;
//--- THE LIVE AI VOTE BOARD, and it exists to keep one signal out of another signal's business.
//---
//--- g_LiveAISignedConfidence above is written once per tick and read by the intelligent trailing stop.
//--- With ONE AI signal that is exactly right. With several (an ensemble) every member wrote it
//--- unconditionally, last writer won, and an LSTM entry's stop was moved by whichever member's OnTick
//--- happened to run last (user-identified 2026-08-17).
//---
//--- The obvious patch - have a member average its siblings - trades a scheduling bug for a coupling bug,
//--- and this EA is deliberately built the other way: every signal runs in its own instance, minds its own
//--- state, and VOTES to the orchestrator, which is the only thing allowed to combine opinions. So the
//--- board below is a publish/aggregate pair with that split enforced by shape:
//--- - a member writes ONLY its own slot (PublishAIVote), never reads another's;
//--- - the orchestrator (CExpertSignalCustom::LiveSignedConfidence) calls AggregateAIVotes() to combine.
//--- Same contract as every other global here: one-way, same-tick, no back-pointer into the wizard chain.
//---
//--- The mean, matching the live open decision (a weighted-average vote, not unanimity) and the ensemble
//--- gate's combined-vote score. A member that abstains publishes 0 and dilutes, exactly as it does there;
//--- a member still training publishes 0, so a half-trained ensemble reads WEAKER rather than louder,
//--- which is the safe direction for something that can close a position.
#define AI_VOTE_BOARD_MAX 8
double g_AIVoteBoard[AI_VOTE_BOARD_MAX];
bool g_AIVoteBoardUsed[AI_VOTE_BOARD_MAX];
void PublishAIVote(int slot, double signedConfidence)
{
if(slot < 0 || slot >= AI_VOTE_BOARD_MAX)
return;
g_AIVoteBoard[slot] = signedConfidence;
g_AIVoteBoardUsed[slot] = true;
}
double AggregateAIVotes(void)
{
double sum = 0.0;
int n = 0;
for(int i = 0; i < AI_VOTE_BOARD_MAX; i++)
if(g_AIVoteBoardUsed[i])
{
sum += g_AIVoteBoard[i];
n++;
}
return (n > 0) ? sum / n : 0.0;
}
//--- CombinedConfidence(source) lived here and collapsed the two numbers above into one 0..1
//--- magnitude per the Confidence_Source input. Removed 2026-08-25 with that input and with every
//--- mode that consumed its result. The journal records the two numbers SEPARATELY and always did,
//--- so nothing is lost: a blend can be computed from the recorded columns whenever there is a
//--- reason to believe in one, which is the correct order for that operation.
//+------------------------------------------------------------------+