diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..14ece33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.ex5 +*.log diff --git a/MQL5/Experts/MultiAgentTest/Core/Orchestrator.mqh b/MQL5/Experts/MultiAgentTest/Core/Orchestrator.mqh index 9f72a8b..3a6e2a7 100644 --- a/MQL5/Experts/MultiAgentTest/Core/Orchestrator.mqh +++ b/MQL5/Experts/MultiAgentTest/Core/Orchestrator.mqh @@ -18,9 +18,55 @@ struct BarSnapshot { double combinedZ; }; +struct AgentSnapshot { + double lastZScore; + double weight; + double rho; + double bias; + double biasStd; + double rhoLearn; + double rawSignal; +}; + +struct TradeRecord { + int ticket; + bool isBuy; + datetime entryTime; + datetime closeTime; + double entryPrice; + double closePrice; + double entryATR; + double entryZ; + double slPrice; + double highestPrice; + double lowestPrice; + int barsHeld; + double maeATR; + double mfeATR; + double actualReturn; + double entryZScores[MAX_AGENTS]; + double entryFeatures[NN_FEATURES]; + string exitReason; +}; + +struct DecisionRecord { + datetime time; + string action; + int direction; + double zScore; + double combinedZ; + double price; + int ticket; + int agreeingCount; + int totalAgents; + double confidence; + double minZ; +}; + // Posizione aperta tracciata con MAE/MFE struct TrackedTrade { int ticket; + datetime entryTime; double entryPrice; double entryATR; double entryZ; @@ -127,6 +173,14 @@ private: BarSnapshot history[MAX_HISTORY]; int histIdx; int histCount; + + // --- Export buffers --- + AgentSnapshot agentHistory[MAX_HISTORY][MAX_AGENTS]; + TradeRecord completedTrades[]; + int completedTradeCount; + DecisionRecord decisionLog[]; + int decisionCount; + int decisionCapacity; void InitCorrelation(int idx) { corrMeanX[idx] = 0; @@ -250,11 +304,20 @@ public: m_trainBuffer = new NNTrainBuffer(); } - histIdx = 0; - histCount = 0; - } + histIdx = 0; + histCount = 0; - ~Orchestrator() { + completedTradeCount = 0; + ArrayResize(completedTrades, 200); + decisionCount = 0; + decisionCapacity = 500; + ArrayResize(decisionLog, decisionCapacity); + for(int ai = 0; ai < MAX_HISTORY; ai++) + for(int aj = 0; aj < MAX_AGENTS; aj++) + agentHistory[ai][aj].lastZScore = 0; + } + + ~Orchestrator() { ReleaseAgents(); if(m_neuralNet) delete m_neuralNet; if(m_trainBuffer) delete m_trainBuffer; @@ -425,10 +488,11 @@ public: return -1; } openTrades[idx].ticket = ticket; - openTrades[idx].entryPrice = price; - openTrades[idx].entryATR = MathMax(atr, 1e-10); - openTrades[idx].entryZ = z; - openTrades[idx].isBuy = isBuy; + openTrades[idx].entryPrice = price; + openTrades[idx].entryATR = MathMax(atr, 1e-10); + openTrades[idx].entryZ = z; + openTrades[idx].isBuy = isBuy; + openTrades[idx].entryTime = TimeCurrent(); openTrades[idx].highestPrice = price; openTrades[idx].lowestPrice = price; openTrades[idx].barsHeld = 0; @@ -463,11 +527,40 @@ openTrades[idx].ticket = ticket; return idx; } - void OnTradeOpen(int ticket, double price, double atr) { - AddTrade(ticket, price, atr, combinedZ, combinedZ > 0); - } - -void OnTradeClose(int ticket, double closePrice) { + void OnTradeOpen(int ticket, double price, double atr) { + AddTrade(ticket, price, atr, combinedZ, combinedZ > 0); + LogDecision("ENTRY", combinedZ > 0 ? 1 : -1, 0, price, ticket); + } + + void LogDecision(string action, int dir, double minZ, double price, int ticket = 0) { + if(decisionCount >= decisionCapacity) { + decisionCapacity *= 2; + ArrayResize(decisionLog, decisionCapacity); + } + DecisionRecord d; + d.time = TimeCurrent(); + d.action = action; + d.direction = dir; + d.zScore = MathAbs(combinedZ); + d.combinedZ = combinedZ; + d.price = price; + d.ticket = ticket; + d.agreeingCount = 0; + d.totalAgents = agentCount; + d.confidence = MathAbs(combinedZ); + d.minZ = minZ; + if(action == "SIGNAL" || action == "ENTRY") { + for(int i=0; i 0.1) { + if((agents[i].lastZScore > 0) == (dir > 0)) d.agreeingCount++; + } + } + } + decisionLog[decisionCount] = d; + decisionCount++; + } + +void OnTradeClose(int ticket, double closePrice, string exitReason = "MANUAL") { // Trova il trade nell'array int idx = -1; for(int i=0; i= MAX_HISTORY) ? histIdx : 0; + for(int i=0; i= MAX_HISTORY) ? histIdx : 0; + for(int i=0; i=0; i--) { @@ -409,6 +421,10 @@ void LogSignal(const MarketData &data, const FinalSignal &fs) { } printCounter++; + // Log decision even for non-actionable signals + double minZ = (Inp_MinZ > 0) ? Inp_MinZ : orchestrator.AdaptiveMinZ(); + orchestrator.LogDecision("SIGNAL", fs.direction, minZ, data.Close(0)); + if(MathAbs(fs.zScore) > Inp_MinZ) { Print(log); Print(" Agents: ", fs.contributingAgents); @@ -438,7 +454,7 @@ void OnTrade() { // Trade closed by SL/TP (not by ManagePositions) bool isBuy = orchestrator.IsBuyTrade(tkt); double closePrice = isBuy ? SymbolInfoDouble(sym, SYMBOL_BID) : SymbolInfoDouble(sym, SYMBOL_ASK); - orchestrator.OnTradeClose(tkt, closePrice); + orchestrator.OnTradeClose(tkt, closePrice, "SLTP"); onTradeCloses++; Print("SL/TP chiuso trade #", tkt, " (totale SL/TP: ", onTradeCloses, ")"); if(onTradeCloses % saveInterval == 0)