Fix MQL5 compile: rename 'input' params in NeuralNet (keyword conflict), replace Orchestrator pointers with direct array access (MQL5 doesn't support struct pointers)

This commit is contained in:
pietro_giacobazzi
2026-06-13 15:18:49 +02:00
parent c70c2f28ce
commit a29befcd67
2 changed files with 128 additions and 133 deletions
@@ -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];
}
+122 -127
View File
@@ -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<agentCount; i++)
t.entryZScores[i] = agents[i].lastZScore;
openTrades[idx].entryZScores[i] = agents[i].lastZScore;
// Feature vector per NN
for(int f = 0; f < NN_FEATURES; f++) t.entryFeatures[f] = 0.0;
for(int f = 0; f < NN_FEATURES; f++) openTrades[idx].entryFeatures[f] = 0.0;
for(int i=0; i<agentCount; i++) {
if(agents[i].name == "Hurst") t.entryFeatures[0] = agents[i].lastZScore;
else if(agents[i].name == "ADX") t.entryFeatures[1] = agents[i].lastZScore;
else if(agents[i].name == "MA") t.entryFeatures[2] = agents[i].lastZScore;
else if(agents[i].name == "Momentum") t.entryFeatures[3] = agents[i].lastZScore;
else if(agents[i].name == "Consensus") t.entryFeatures[4] = agents[i].lastZScore;
else if(agents[i].name == "Hunter") t.entryFeatures[5] = agents[i].lastZScore;
if(agents[i].name == "Hurst") openTrades[idx].entryFeatures[0] = agents[i].lastZScore;
else if(agents[i].name == "ADX") openTrades[idx].entryFeatures[1] = agents[i].lastZScore;
else if(agents[i].name == "MA") openTrades[idx].entryFeatures[2] = agents[i].lastZScore;
else if(agents[i].name == "Momentum") openTrades[idx].entryFeatures[3] = agents[i].lastZScore;
else if(agents[i].name == "Consensus") openTrades[idx].entryFeatures[4] = agents[i].lastZScore;
else if(agents[i].name == "Hunter") openTrades[idx].entryFeatures[5] = agents[i].lastZScore;
}
t.entryFeatures[6] = SHARED_regimeAgreement;
t.entryFeatures[7] = SHARED_trendStrength;
openTrades[idx].entryFeatures[6] = SHARED_regimeAgreement;
openTrades[idx].entryFeatures[7] = SHARED_trendStrength;
// SL iniziale adattivo
double slWidth = AdaptiveSLWidth();
t.slPrice = isBuy ? price - atr * slWidth : price + atr * slWidth;
openTrades[idx].slPrice = isBuy ? price - atr * slWidth : price + atr * slWidth;
Print("Trade #", ticket, " ", isBuy ? "BUY" : "SELL",
" entry=", price, " z=", StringFormat("%+.3f", z),
" SL=", StringFormat("%.5f", t.slPrice),
" SL=", StringFormat("%.5f", openTrades[idx].slPrice),
" (", StringFormat("%.1f", slWidth), " ATR)");
return idx;
}
@@ -476,44 +475,42 @@ void OnTradeClose(int ticket, double closePrice) {
}
if(idx < 0) return;
TrackedTrade *t = &openTrades[idx];
// Calcola MAE/MFE finali
if(openTrades[idx].isBuy) {
openTrades[idx].maeATR = (openTrades[idx].entryPrice - openTrades[idx].lowestPrice) / openTrades[idx].entryATR;
openTrades[idx].mfeATR = (openTrades[idx].highestPrice - openTrades[idx].entryPrice) / openTrades[idx].entryATR;
} else {
openTrades[idx].maeATR = (openTrades[idx].highestPrice - openTrades[idx].entryPrice) / openTrades[idx].entryATR;
openTrades[idx].mfeATR = (openTrades[idx].entryPrice - openTrades[idx].lowestPrice) / openTrades[idx].entryATR;
}
// Calcola MAE/MFE finali
if(t.isBuy) {
t.maeATR = (t.entryPrice - t.lowestPrice) / t.entryATR;
t.mfeATR = (t.highestPrice - t.entryPrice) / t.entryATR;
} else {
t.maeATR = (t.highestPrice - t.entryPrice) / t.entryATR;
t.mfeATR = (t.entryPrice - t.lowestPrice) / t.entryATR;
}
// ROI in ATR (positivo = profitto nella direzione del trade)
double actualReturn = openTrades[idx].isBuy
? (closePrice - openTrades[idx].entryPrice) / openTrades[idx].entryATR
: (openTrades[idx].entryPrice - closePrice) / openTrades[idx].entryATR;
// ROI in ATR (positivo = profitto nella direzione del trade)
double actualReturn = t.isBuy
? (closePrice - t.entryPrice) / t.entryATR
: (t.entryPrice - closePrice) / t.entryATR;
returnStats.Update(actualReturn);
maeStats.Update(openTrades[idx].maeATR);
mfeStats.Update(openTrades[idx].mfeATR);
if(actualReturn > 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<agentCount; i++) {
if(MathAbs(t.entryZScores[i]) < sigThr) continue;
UpdateCorrelation(i, t.entryZScores[i], actualReturnZ);
double rho = GetCorrelation(i);
UpdateCorrelation(i, openTrades[idx].entryZScores[i], actualReturnZ);
double rho = GetCorrelation(i);
agents[i].weight = MathMax(weightMin, rho);
agents[i].weight = MathMax(weightMin, rho);
agents[i].Learn(t.entryZScores[i], actualReturnZ);
agents[i].Learn(openTrades[idx].entryZScores[i], actualReturnZ);
double bias = agents[i].predictionError.Mean();
double biasStd = agents[i].predictionError.Std();
double rhoLearn = agents[i].predCorr.Ready() ? agents[i].predCorr.Correlation() : 0;
double bias = agents[i].predictionError.Mean();
double biasStd = agents[i].predictionError.Std();
double rhoLearn = agents[i].predCorr.Ready() ? agents[i].predCorr.Correlation() : 0;
Print(" ", agents[i].name,
" | pred=", StringFormat("%+.2f", t.entryZScores[i]),
" | ρ=", StringFormat("%+.3f", rho),
" | w=", StringFormat("%.3f", agents[i].weight),
" | bias=", StringFormat("%+.4f", bias),
" | biasσ=", StringFormat("%.4f", biasStd),
" | ρ_learn=", StringFormat("%+.3f", rhoLearn));
}
Print(" ", agents[i].name,
" | pred=", StringFormat("%+.2f", openTrades[idx].entryZScores[i]),
" | ρ=", StringFormat("%+.3f", rho),
" | w=", StringFormat("%.3f", agents[i].weight),
" | bias=", StringFormat("%+.4f", bias),
" | biasσ=", StringFormat("%.4f", biasStd),
" | ρ_learn=", StringFormat("%+.3f", rhoLearn));
}
// --- Neural Network: colleziona training sample ---
if(m_trainMode && m_trainBuffer != NULL && m_neuralNet != NULL) {
double features[NN_FEATURES];
double target[NN_TARGETS];
for(int f = 0; f < NN_FEATURES; f++) features[f] = t.entryFeatures[f];
// --- Neural Network: colleziona training sample ---
if(m_trainMode && m_trainBuffer != NULL && m_neuralNet != NULL) {
double features[NN_FEATURES];
double target[NN_TARGETS];
for(int f = 0; f < NN_FEATURES; f++) features[f] = openTrades[idx].entryFeatures[f];
target[0] = 0; target[1] = 0; target[2] = 0;
int tradeDir = t.isBuy ? 1 : -1;
target[0] = 0; target[1] = 0; target[2] = 0;
int tradeDir = openTrades[idx].isBuy ? 1 : -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;
}
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<maxOpenTrades; i++) {
if(!openTrades[i].active) continue;
TrackedTrade *t = &openTrades[i];
if(high > 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<maxOpenTrades; i++) {
if(!openTrades[i].active) continue;
if(high > 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<maxOpenTrades; i++) {
if(!openTrades[i].active) continue;
TrackedTrade *t = &openTrades[i];
// Trailing stop: sposta SL dopo che il profitto supera la soglia
void TrailStops() {
for(int i=0; i<maxOpenTrades; i++) {
if(!openTrades[i].active) continue;
double profitATR = t.isBuy
? (t.highestPrice - t.entryPrice) / t.entryATR
: (t.entryPrice - t.lowestPrice) / t.entryATR;
double profitATR = openTrades[i].isBuy
? (openTrades[i].highestPrice - openTrades[i].entryPrice) / openTrades[i].entryATR
: (openTrades[i].entryPrice - openTrades[i].lowestPrice) / openTrades[i].entryATR;
double trigger = AdaptiveTrailTrigger();
if(profitATR > 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) {