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:
@@ -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];
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user