diff --git a/MQL5/Experts/MultiAgentTest/Core/NeuralNet.mqh b/MQL5/Experts/MultiAgentTest/Core/NeuralNet.mqh index fdd82e0..e15bc71 100644 --- a/MQL5/Experts/MultiAgentTest/Core/NeuralNet.mqh +++ b/MQL5/Experts/MultiAgentTest/Core/NeuralNet.mqh @@ -498,9 +498,9 @@ for(int i = 0; i < m_hidden; i++) { first, last, best, bestEpoch+1, ArraySize(m_lossHistory)); } - int Predict(vector &input) { - vector output; - Forward(input, output); +int Predict(vector &inp) { + vector output; + Forward(inp, output); int bestIdx = 0; double bestVal = output[0]; for(int i = 1; i < m_outputs; i++) { @@ -512,9 +512,9 @@ for(int i = 0; i < m_hidden; i++) { return bestIdx; } - double GetCombinedZ(vector &input) { - vector output; - Forward(input, output); +double GetCombinedZ(vector &inp) { + vector output; + Forward(inp, output); return output[0] - output[2]; } diff --git a/MQL5/Experts/MultiAgentTest/Core/Orchestrator.mqh b/MQL5/Experts/MultiAgentTest/Core/Orchestrator.mqh index 38585bb..6b5bc39 100644 --- a/MQL5/Experts/MultiAgentTest/Core/Orchestrator.mqh +++ b/MQL5/Experts/MultiAgentTest/Core/Orchestrator.mqh @@ -424,42 +424,41 @@ public: Print("ERROR: slot non disponibile nonostante capacity expansion"); return -1; } -TrackedTrade *t = &openTrades[idx]; - t.ticket = ticket; - t.entryPrice = price; - t.entryATR = MathMax(atr, 1e-10); - t.entryZ = z; - t.isBuy = isBuy; - t.highestPrice = price; - t.lowestPrice = price; - t.barsHeld = 0; - t.maeATR = 0; - t.mfeATR = 0; - t.active = true; +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].highestPrice = price; + openTrades[idx].lowestPrice = price; + openTrades[idx].barsHeld = 0; + openTrades[idx].maeATR = 0; + openTrades[idx].mfeATR = 0; + openTrades[idx].active = true; for(int i=0; i 0) maeWinStats.Update(openTrades[idx].maeATR); - returnStats.Update(actualReturn); - maeStats.Update(t.maeATR); - mfeStats.Update(t.mfeATR); - if(actualReturn > 0) maeWinStats.Update(t.maeATR); + tradeReturns[tradeCount % ROLLING_TRADES] = actualReturn; + tradeCount++; + if(actualReturn > 0) winCount++; - tradeReturns[tradeCount % ROLLING_TRADES] = actualReturn; - tradeCount++; - if(actualReturn > 0) winCount++; + double eq = AccountInfoDouble(ACCOUNT_EQUITY); + if(eq > peakEquity) peakEquity = eq; + double dd = (peakEquity > 0) ? (peakEquity - eq) / peakEquity : 0; + if(dd > maxDrawdown) maxDrawdown = dd; + double actualReturnZ = returnStats.RawZScore(actualReturn); - double eq = AccountInfoDouble(ACCOUNT_EQUITY); - if(eq > peakEquity) peakEquity = eq; - double dd = (peakEquity > 0) ? (peakEquity - eq) / peakEquity : 0; - if(dd > maxDrawdown) maxDrawdown = dd; - double actualReturnZ = returnStats.RawZScore(actualReturn); - - Print("=== Learning: Trade #", ticket, " ", t.isBuy ? "BUY" : "SELL", " chiuso ==="); - Print(" Return: ", StringFormat("%+.2f ATR", actualReturn), - " | MAE: ", StringFormat("%.2f", t.maeATR), - " | MFE: ", StringFormat("%.2f", t.mfeATR), - " | bars: ", t.barsHeld); - Print(" Entry z=", StringFormat("%+.3f", t.entryZ), - " | SL width: ", StringFormat("%.2f ATR", AdaptiveSLWidth())); + Print("=== Learning: Trade #", ticket, " ", openTrades[idx].isBuy ? "BUY" : "SELL", " chiuso ==="); + Print(" Return: ", StringFormat("%+.2f ATR", actualReturn), + " | MAE: ", StringFormat("%.2f", openTrades[idx].maeATR), + " | MFE: ", StringFormat("%.2f", openTrades[idx].mfeATR), + " | bars: ", openTrades[idx].barsHeld); + Print(" Entry z=", StringFormat("%+.3f", openTrades[idx].entryZ), + " | SL width: ", StringFormat("%.2f ATR", AdaptiveSLWidth())); double sigThr = combinedZStats.Ready() ? combinedZStats.Std() / MathSqrt(MathMax(1, agentCount)) @@ -521,55 +518,55 @@ void OnTradeClose(int ticket, double closePrice) { for(int i=0; i 0) { - if(tradeDir == 1) target[0] = 1; - else target[2] = 1; - } else { - if(tradeDir == 1) target[2] = 1; - else target[0] = 1; - } + if(actualReturn > 0) { + if(tradeDir == 1) target[0] = 1; + else target[2] = 1; + } else { + if(tradeDir == 1) target[2] = 1; + else target[0] = 1; + } - double sampleWeight = MathAbs(actualReturn) + 1.0; // trade profittevoli/perdenti pesano di più - m_trainBuffer.Add(features, target, sampleWeight); + double sampleWeight = MathAbs(actualReturn) + 1.0; // trade profittevoli/perdenti pesano di più + m_trainBuffer.Add(features, target, sampleWeight); - if(m_trainBuffer.Count() < 20) - Print(" NN sample #", m_trainBuffer.Count(), " collected (w=", StringFormat("%.2f", sampleWeight), ")"); + if(m_trainBuffer.Count() < 20) + Print(" NN sample #", m_trainBuffer.Count(), " collected (w=", StringFormat("%.2f", sampleWeight), ")"); - if(m_trainBuffer.Count() % 50 == 0 && m_trainBuffer.Count() >= 20) { - if(m_useNeural) { - TrainNN(); - string nnFn = (m_modelFilename != "") ? m_modelFilename : "TR_Agent_NN_v1.dat"; - m_neuralNet.Save(nnFn); - Print(" NN auto-saved to ", nnFn, " after ", m_trainBuffer.Count(), " samples"); + if(m_trainBuffer.Count() % 50 == 0 && m_trainBuffer.Count() >= 20) { + if(m_useNeural) { + TrainNN(); + string nnFn = (m_modelFilename != "") ? m_modelFilename : "TR_Agent_NN_v1.dat"; + m_neuralNet.Save(nnFn); + Print(" NN auto-saved to ", nnFn, " after ", m_trainBuffer.Count(), " samples"); } } } @@ -588,40 +585,38 @@ void OnTradeClose(int ticket, double closePrice) { } // Aggiorna MAE/MFE per tutti i trade aperti (chiamato ogni barra) - void UpdateOpenTrades(double high, double low) { - for(int i=0; i t.highestPrice) t.highestPrice = high; - if(low < t.lowestPrice) t.lowestPrice = low; - t.barsHeld++; - } - } + void UpdateOpenTrades(double high, double low) { + for(int i=0; i openTrades[i].highestPrice) openTrades[i].highestPrice = high; + if(low < openTrades[i].lowestPrice) openTrades[i].lowestPrice = low; + openTrades[i].barsHeld++; + } + } - // Trailing stop: sposta SL dopo che il profitto supera la soglia - void TrailStops() { - for(int i=0; i trigger) { - double offset = AdaptiveTrailOffset(); - double newSL; - if(t.isBuy) { - newSL = t.highestPrice - offset * t.entryATR; - if(newSL > t.slPrice) t.slPrice = newSL; - } else { - newSL = t.lowestPrice + offset * t.entryATR; - if(newSL < t.slPrice) t.slPrice = newSL; - } - } - } - } + double trigger = AdaptiveTrailTrigger(); + if(profitATR > trigger) { + double offset = AdaptiveTrailOffset(); + double newSL; + if(openTrades[i].isBuy) { + newSL = openTrades[i].highestPrice - offset * openTrades[i].entryATR; + if(newSL > openTrades[i].slPrice) openTrades[i].slPrice = newSL; + } else { + newSL = openTrades[i].lowestPrice + offset * openTrades[i].entryATR; + if(newSL < openTrades[i].slPrice) openTrades[i].slPrice = newSL; + } + } + } + } // Trade da chiudere per inversione di segnale (ritorna array di ticket) void GetTradesToClose(int &closeTickets[], double currentZ, double minZ) {