Warrior_EA/Expert/Chart/AIBaseChartView.mqh
AnimateDread b92e233b88 fix(chart): a deployed model rescans history to rebuild its vote arrows
The sidecar added in 484a9d8 restores the vote arrows from the previous
session - but there was no previous session to restore from, and a
deployed ensemble could never produce one.

The overlay that draws the vote layer replays each member's
m_overlaySigSnap, published in exactly one place: RankTiersFromOos, at
pass-3 completion. A converged model runs no further eras. So after a
restart every member's snapshot was empty, would never fill, the sweep
had nothing to replay and the chart stayed blank permanently - no route
back by any path.

The chart rescan is the route: it runs the DEPLOYED net forward over
history and rebuilds the per-bar cache, which is the same quantity pass 3
produces, obtained without training. It already existed for the panel's
Show-Signals button; it just never handed its result to the overlay, so
on the default filtered view a rescan rebuilt only the RAW per-member
layer - the one that is hidden - and appeared to do nothing.

- PublishOverlaySnapshotFromCache() extracted from RankTiersFromOos, so
  the era end and a completed rescan publish through one implementation.
- A completed rescan now calls it, which also arms the sweep.
- PollTraining auto-arms one rescan for a model that is converged, has no
  snapshot, and is on the filtered view. One-shot: a model that
  legitimately calls Neutral everywhere must not rescan forever chasing a
  snapshot that is correctly empty. On the timer, not in OnInit - it is a
  full feedForward per bar over up to 5000 bars and drains in the same
  time-boxed slices as a manual rescan.

Together with the sidecar this closes both halves: the rescan covers the
first session and any chart whose file was lost or invalidated by a
threshold change; the sidecar covers every session after one is saved.

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

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

83 lines
4.5 KiB
MQL5

//+------------------------------------------------------------------+
//| Warrior_EA |
//| AnimateDread |
//| |
//| Adapter: CExpertSignalAIBase seen as a CChartView. |
//+------------------------------------------------------------------+
#ifndef WARRIOR_CHART_AIBASECHARTVIEW_MQH
#define WARRIOR_CHART_AIBASECHARTVIEW_MQH
#include "IChartView.mqh"
class CExpertSignalAIBase;
//+------------------------------------------------------------------+
//| THE ONE PLACE THAT KNOWS BOTH SIDES - see Training\AIBaseTrainingData.mqh for the full rationale |
//| (MQL5 gives a class exactly one base, so the signal cannot implement CChartView directly and owns |
//| one of these instead). Every method is a forward; it holds a borrowed pointer and never frees it. |
//+------------------------------------------------------------------+
class CAIBaseChartView : public CChartView
{
private:
CExpertSignalAIBase *m_owner; // BORROWED - the signal owns this object, not the reverse
public:
CAIBaseChartView(void) : m_owner(NULL) { }
~CAIBaseChartView(void) { m_owner = NULL; }
void Bind(CExpertSignalAIBase *owner) { m_owner = owner; }
virtual string Id(void) override;
virtual string FileName(void) override;
virtual string ArrowPrefix(void) override;
virtual ENUM_TIMEFRAMES Period(void) override;
virtual int Digits(void) override;
virtual string DisplayNameForChart(void) override;
virtual bool ModelLoadedFromDisk(void) override;
virtual bool TrainingComplete(void) override;
virtual bool BothDirectionsTradeable(void) override;
virtual int SignalClusterWindow(void) override;
virtual bool Stopping(void) override;
virtual datetime BarTime(const int idx) override;
virtual double BarClose(const int idx) override;
virtual int HistoryBars(void) override;
virtual int OutputNeuronsCount(void) override;
virtual bool NetReady(void) override;
virtual int AvailableBars(void) override;
virtual bool ResizeBuffers(const int barIndex) override;
virtual bool RefreshData(void) override;
virtual int ServableBars(const int want, const string context) override;
virtual void EnsureShadowNet(void) override;
virtual bool ScoreBarForRescan(const int idx, double &rawSignal, double &adjustedSignal) override;
virtual ENUM_SIGNAL ToSignal(const double value) override;
virtual int PredictionCacheSize(void) override;
virtual double PredictionAt(const int idx) override;
virtual void SetPredictionAt(const int idx, const double value) override;
virtual void ResizePredictionCache(const int size, const double fillValue) override;
virtual void PublishOverlaySnapshot(void) override;
virtual long EraCount(void) override;
virtual long CumIsTotal(void) override;
virtual long CumIsCorrect(void) override;
virtual long CumOosTotal(void) override;
virtual long CumOosCorrect(void) override;
virtual void OosTally(int &buyPredicted, int &sellPredicted, int &buyPredictedHits, int &sellPredictedHits) override;
virtual string PassLabel(void) override;
virtual int PassProgressPct(void) override;
virtual int OosSplitPct(void) override;
virtual int OosSamples(void) override;
virtual void ClassCounts(int &predBuy, int &predSell, int &predNeutral,
int &trueBuy, int &trueSell, int &trueNeutral) override;
virtual void OosRecallPct(int &buyRecallPct, int &sellRecallPct) override;
virtual void OosLivePrecision(int &buyPrecPct, int &buyFired, int &sellPrecPct, int &sellFired) override;
virtual double Forecast(void) override;
virtual double ErrorPct(void) override;
virtual double OosForecast(void) override;
virtual double OosErrorPct(void) override;
virtual double NetRecentAverageError(void) override;
virtual bool DisplayInference(void) override;
virtual double LiveVoteContribution(const double signal) override;
virtual double VoteCapableWeight(void) override;
virtual void PublishStatus(const string text, const bool force) override;
};
#endif // WARRIOR_CHART_AIBASECHARTVIEW_MQH
//+------------------------------------------------------------------+