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));
|
first, last, best, bestEpoch+1, ArraySize(m_lossHistory));
|
||||||
}
|
}
|
||||||
|
|
||||||
int Predict(vector &input) {
|
int Predict(vector &inp) {
|
||||||
vector output;
|
vector output;
|
||||||
Forward(input, output);
|
Forward(inp, output);
|
||||||
int bestIdx = 0;
|
int bestIdx = 0;
|
||||||
double bestVal = output[0];
|
double bestVal = output[0];
|
||||||
for(int i = 1; i < m_outputs; i++) {
|
for(int i = 1; i < m_outputs; i++) {
|
||||||
@@ -512,9 +512,9 @@ for(int i = 0; i < m_hidden; i++) {
|
|||||||
return bestIdx;
|
return bestIdx;
|
||||||
}
|
}
|
||||||
|
|
||||||
double GetCombinedZ(vector &input) {
|
double GetCombinedZ(vector &inp) {
|
||||||
vector output;
|
vector output;
|
||||||
Forward(input, output);
|
Forward(inp, output);
|
||||||
return output[0] - output[2];
|
return output[0] - output[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -424,42 +424,41 @@ public:
|
|||||||
Print("ERROR: slot non disponibile nonostante capacity expansion");
|
Print("ERROR: slot non disponibile nonostante capacity expansion");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
TrackedTrade *t = &openTrades[idx];
|
openTrades[idx].ticket = ticket;
|
||||||
t.ticket = ticket;
|
openTrades[idx].entryPrice = price;
|
||||||
t.entryPrice = price;
|
openTrades[idx].entryATR = MathMax(atr, 1e-10);
|
||||||
t.entryATR = MathMax(atr, 1e-10);
|
openTrades[idx].entryZ = z;
|
||||||
t.entryZ = z;
|
openTrades[idx].isBuy = isBuy;
|
||||||
t.isBuy = isBuy;
|
openTrades[idx].highestPrice = price;
|
||||||
t.highestPrice = price;
|
openTrades[idx].lowestPrice = price;
|
||||||
t.lowestPrice = price;
|
openTrades[idx].barsHeld = 0;
|
||||||
t.barsHeld = 0;
|
openTrades[idx].maeATR = 0;
|
||||||
t.maeATR = 0;
|
openTrades[idx].mfeATR = 0;
|
||||||
t.mfeATR = 0;
|
openTrades[idx].active = true;
|
||||||
t.active = true;
|
|
||||||
|
|
||||||
for(int i=0; i<agentCount; i++)
|
for(int i=0; i<agentCount; i++)
|
||||||
t.entryZScores[i] = agents[i].lastZScore;
|
openTrades[idx].entryZScores[i] = agents[i].lastZScore;
|
||||||
|
|
||||||
// Feature vector per NN
|
// 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++) {
|
for(int i=0; i<agentCount; i++) {
|
||||||
if(agents[i].name == "Hurst") t.entryFeatures[0] = agents[i].lastZScore;
|
if(agents[i].name == "Hurst") openTrades[idx].entryFeatures[0] = agents[i].lastZScore;
|
||||||
else if(agents[i].name == "ADX") t.entryFeatures[1] = agents[i].lastZScore;
|
else if(agents[i].name == "ADX") openTrades[idx].entryFeatures[1] = agents[i].lastZScore;
|
||||||
else if(agents[i].name == "MA") t.entryFeatures[2] = agents[i].lastZScore;
|
else if(agents[i].name == "MA") openTrades[idx].entryFeatures[2] = agents[i].lastZScore;
|
||||||
else if(agents[i].name == "Momentum") t.entryFeatures[3] = agents[i].lastZScore;
|
else if(agents[i].name == "Momentum") openTrades[idx].entryFeatures[3] = agents[i].lastZScore;
|
||||||
else if(agents[i].name == "Consensus") t.entryFeatures[4] = agents[i].lastZScore;
|
else if(agents[i].name == "Consensus") openTrades[idx].entryFeatures[4] = agents[i].lastZScore;
|
||||||
else if(agents[i].name == "Hunter") t.entryFeatures[5] = agents[i].lastZScore;
|
else if(agents[i].name == "Hunter") openTrades[idx].entryFeatures[5] = agents[i].lastZScore;
|
||||||
}
|
}
|
||||||
t.entryFeatures[6] = SHARED_regimeAgreement;
|
openTrades[idx].entryFeatures[6] = SHARED_regimeAgreement;
|
||||||
t.entryFeatures[7] = SHARED_trendStrength;
|
openTrades[idx].entryFeatures[7] = SHARED_trendStrength;
|
||||||
|
|
||||||
// SL iniziale adattivo
|
// SL iniziale adattivo
|
||||||
double slWidth = AdaptiveSLWidth();
|
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",
|
Print("Trade #", ticket, " ", isBuy ? "BUY" : "SELL",
|
||||||
" entry=", price, " z=", StringFormat("%+.3f", z),
|
" entry=", price, " z=", StringFormat("%+.3f", z),
|
||||||
" SL=", StringFormat("%.5f", t.slPrice),
|
" SL=", StringFormat("%.5f", openTrades[idx].slPrice),
|
||||||
" (", StringFormat("%.1f", slWidth), " ATR)");
|
" (", StringFormat("%.1f", slWidth), " ATR)");
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
@@ -476,44 +475,42 @@ void OnTradeClose(int ticket, double closePrice) {
|
|||||||
}
|
}
|
||||||
if(idx < 0) return;
|
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
|
// ROI in ATR (positivo = profitto nella direzione del trade)
|
||||||
if(t.isBuy) {
|
double actualReturn = openTrades[idx].isBuy
|
||||||
t.maeATR = (t.entryPrice - t.lowestPrice) / t.entryATR;
|
? (closePrice - openTrades[idx].entryPrice) / openTrades[idx].entryATR
|
||||||
t.mfeATR = (t.highestPrice - t.entryPrice) / t.entryATR;
|
: (openTrades[idx].entryPrice - closePrice) / openTrades[idx].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)
|
returnStats.Update(actualReturn);
|
||||||
double actualReturn = t.isBuy
|
maeStats.Update(openTrades[idx].maeATR);
|
||||||
? (closePrice - t.entryPrice) / t.entryATR
|
mfeStats.Update(openTrades[idx].mfeATR);
|
||||||
: (t.entryPrice - closePrice) / t.entryATR;
|
if(actualReturn > 0) maeWinStats.Update(openTrades[idx].maeATR);
|
||||||
|
|
||||||
returnStats.Update(actualReturn);
|
tradeReturns[tradeCount % ROLLING_TRADES] = actualReturn;
|
||||||
maeStats.Update(t.maeATR);
|
tradeCount++;
|
||||||
mfeStats.Update(t.mfeATR);
|
if(actualReturn > 0) winCount++;
|
||||||
if(actualReturn > 0) maeWinStats.Update(t.maeATR);
|
|
||||||
|
|
||||||
tradeReturns[tradeCount % ROLLING_TRADES] = actualReturn;
|
double eq = AccountInfoDouble(ACCOUNT_EQUITY);
|
||||||
tradeCount++;
|
if(eq > peakEquity) peakEquity = eq;
|
||||||
if(actualReturn > 0) winCount++;
|
double dd = (peakEquity > 0) ? (peakEquity - eq) / peakEquity : 0;
|
||||||
|
if(dd > maxDrawdown) maxDrawdown = dd;
|
||||||
|
double actualReturnZ = returnStats.RawZScore(actualReturn);
|
||||||
|
|
||||||
double eq = AccountInfoDouble(ACCOUNT_EQUITY);
|
Print("=== Learning: Trade #", ticket, " ", openTrades[idx].isBuy ? "BUY" : "SELL", " chiuso ===");
|
||||||
if(eq > peakEquity) peakEquity = eq;
|
Print(" Return: ", StringFormat("%+.2f ATR", actualReturn),
|
||||||
double dd = (peakEquity > 0) ? (peakEquity - eq) / peakEquity : 0;
|
" | MAE: ", StringFormat("%.2f", openTrades[idx].maeATR),
|
||||||
if(dd > maxDrawdown) maxDrawdown = dd;
|
" | MFE: ", StringFormat("%.2f", openTrades[idx].mfeATR),
|
||||||
double actualReturnZ = returnStats.RawZScore(actualReturn);
|
" | bars: ", openTrades[idx].barsHeld);
|
||||||
|
Print(" Entry z=", StringFormat("%+.3f", openTrades[idx].entryZ),
|
||||||
Print("=== Learning: Trade #", ticket, " ", t.isBuy ? "BUY" : "SELL", " chiuso ===");
|
" | SL width: ", StringFormat("%.2f ATR", AdaptiveSLWidth()));
|
||||||
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()));
|
|
||||||
|
|
||||||
double sigThr = combinedZStats.Ready()
|
double sigThr = combinedZStats.Ready()
|
||||||
? combinedZStats.Std() / MathSqrt(MathMax(1, agentCount))
|
? combinedZStats.Std() / MathSqrt(MathMax(1, agentCount))
|
||||||
@@ -521,55 +518,55 @@ void OnTradeClose(int ticket, double closePrice) {
|
|||||||
for(int i=0; i<agentCount; i++) {
|
for(int i=0; i<agentCount; i++) {
|
||||||
if(MathAbs(t.entryZScores[i]) < sigThr) continue;
|
if(MathAbs(t.entryZScores[i]) < sigThr) continue;
|
||||||
|
|
||||||
UpdateCorrelation(i, t.entryZScores[i], actualReturnZ);
|
UpdateCorrelation(i, openTrades[idx].entryZScores[i], actualReturnZ);
|
||||||
double rho = GetCorrelation(i);
|
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 bias = agents[i].predictionError.Mean();
|
||||||
double biasStd = agents[i].predictionError.Std();
|
double biasStd = agents[i].predictionError.Std();
|
||||||
double rhoLearn = agents[i].predCorr.Ready() ? agents[i].predCorr.Correlation() : 0;
|
double rhoLearn = agents[i].predCorr.Ready() ? agents[i].predCorr.Correlation() : 0;
|
||||||
|
|
||||||
Print(" ", agents[i].name,
|
Print(" ", agents[i].name,
|
||||||
" | pred=", StringFormat("%+.2f", t.entryZScores[i]),
|
" | pred=", StringFormat("%+.2f", openTrades[idx].entryZScores[i]),
|
||||||
" | ρ=", StringFormat("%+.3f", rho),
|
" | ρ=", StringFormat("%+.3f", rho),
|
||||||
" | w=", StringFormat("%.3f", agents[i].weight),
|
" | w=", StringFormat("%.3f", agents[i].weight),
|
||||||
" | bias=", StringFormat("%+.4f", bias),
|
" | bias=", StringFormat("%+.4f", bias),
|
||||||
" | biasσ=", StringFormat("%.4f", biasStd),
|
" | biasσ=", StringFormat("%.4f", biasStd),
|
||||||
" | ρ_learn=", StringFormat("%+.3f", rhoLearn));
|
" | ρ_learn=", StringFormat("%+.3f", rhoLearn));
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Neural Network: colleziona training sample ---
|
// --- Neural Network: colleziona training sample ---
|
||||||
if(m_trainMode && m_trainBuffer != NULL && m_neuralNet != NULL) {
|
if(m_trainMode && m_trainBuffer != NULL && m_neuralNet != NULL) {
|
||||||
double features[NN_FEATURES];
|
double features[NN_FEATURES];
|
||||||
double target[NN_TARGETS];
|
double target[NN_TARGETS];
|
||||||
for(int f = 0; f < NN_FEATURES; f++) features[f] = t.entryFeatures[f];
|
for(int f = 0; f < NN_FEATURES; f++) features[f] = openTrades[idx].entryFeatures[f];
|
||||||
|
|
||||||
target[0] = 0; target[1] = 0; target[2] = 0;
|
target[0] = 0; target[1] = 0; target[2] = 0;
|
||||||
int tradeDir = t.isBuy ? 1 : -1;
|
int tradeDir = openTrades[idx].isBuy ? 1 : -1;
|
||||||
|
|
||||||
if(actualReturn > 0) {
|
if(actualReturn > 0) {
|
||||||
if(tradeDir == 1) target[0] = 1;
|
if(tradeDir == 1) target[0] = 1;
|
||||||
else target[2] = 1;
|
else target[2] = 1;
|
||||||
} else {
|
} else {
|
||||||
if(tradeDir == 1) target[2] = 1;
|
if(tradeDir == 1) target[2] = 1;
|
||||||
else target[0] = 1;
|
else target[0] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
double sampleWeight = MathAbs(actualReturn) + 1.0; // trade profittevoli/perdenti pesano di più
|
double sampleWeight = MathAbs(actualReturn) + 1.0; // trade profittevoli/perdenti pesano di più
|
||||||
m_trainBuffer.Add(features, target, sampleWeight);
|
m_trainBuffer.Add(features, target, sampleWeight);
|
||||||
|
|
||||||
if(m_trainBuffer.Count() < 20)
|
if(m_trainBuffer.Count() < 20)
|
||||||
Print(" NN sample #", m_trainBuffer.Count(), " collected (w=", StringFormat("%.2f", sampleWeight), ")");
|
Print(" NN sample #", m_trainBuffer.Count(), " collected (w=", StringFormat("%.2f", sampleWeight), ")");
|
||||||
|
|
||||||
if(m_trainBuffer.Count() % 50 == 0 && m_trainBuffer.Count() >= 20) {
|
if(m_trainBuffer.Count() % 50 == 0 && m_trainBuffer.Count() >= 20) {
|
||||||
if(m_useNeural) {
|
if(m_useNeural) {
|
||||||
TrainNN();
|
TrainNN();
|
||||||
string nnFn = (m_modelFilename != "") ? m_modelFilename : "TR_Agent_NN_v1.dat";
|
string nnFn = (m_modelFilename != "") ? m_modelFilename : "TR_Agent_NN_v1.dat";
|
||||||
m_neuralNet.Save(nnFn);
|
m_neuralNet.Save(nnFn);
|
||||||
Print(" NN auto-saved to ", nnFn, " after ", m_trainBuffer.Count(), " samples");
|
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)
|
// Aggiorna MAE/MFE per tutti i trade aperti (chiamato ogni barra)
|
||||||
void UpdateOpenTrades(double high, double low) {
|
void UpdateOpenTrades(double high, double low) {
|
||||||
for(int i=0; i<maxOpenTrades; i++) {
|
for(int i=0; i<maxOpenTrades; i++) {
|
||||||
if(!openTrades[i].active) continue;
|
if(!openTrades[i].active) continue;
|
||||||
TrackedTrade *t = &openTrades[i];
|
if(high > openTrades[i].highestPrice) openTrades[i].highestPrice = high;
|
||||||
if(high > t.highestPrice) t.highestPrice = high;
|
if(low < openTrades[i].lowestPrice) openTrades[i].lowestPrice = low;
|
||||||
if(low < t.lowestPrice) t.lowestPrice = low;
|
openTrades[i].barsHeld++;
|
||||||
t.barsHeld++;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Trailing stop: sposta SL dopo che il profitto supera la soglia
|
// Trailing stop: sposta SL dopo che il profitto supera la soglia
|
||||||
void TrailStops() {
|
void TrailStops() {
|
||||||
for(int i=0; i<maxOpenTrades; i++) {
|
for(int i=0; i<maxOpenTrades; i++) {
|
||||||
if(!openTrades[i].active) continue;
|
if(!openTrades[i].active) continue;
|
||||||
TrackedTrade *t = &openTrades[i];
|
|
||||||
|
|
||||||
double profitATR = t.isBuy
|
double profitATR = openTrades[i].isBuy
|
||||||
? (t.highestPrice - t.entryPrice) / t.entryATR
|
? (openTrades[i].highestPrice - openTrades[i].entryPrice) / openTrades[i].entryATR
|
||||||
: (t.entryPrice - t.lowestPrice) / t.entryATR;
|
: (openTrades[i].entryPrice - openTrades[i].lowestPrice) / openTrades[i].entryATR;
|
||||||
|
|
||||||
double trigger = AdaptiveTrailTrigger();
|
double trigger = AdaptiveTrailTrigger();
|
||||||
if(profitATR > trigger) {
|
if(profitATR > trigger) {
|
||||||
double offset = AdaptiveTrailOffset();
|
double offset = AdaptiveTrailOffset();
|
||||||
double newSL;
|
double newSL;
|
||||||
if(t.isBuy) {
|
if(openTrades[i].isBuy) {
|
||||||
newSL = t.highestPrice - offset * t.entryATR;
|
newSL = openTrades[i].highestPrice - offset * openTrades[i].entryATR;
|
||||||
if(newSL > t.slPrice) t.slPrice = newSL;
|
if(newSL > openTrades[i].slPrice) openTrades[i].slPrice = newSL;
|
||||||
} else {
|
} else {
|
||||||
newSL = t.lowestPrice + offset * t.entryATR;
|
newSL = openTrades[i].lowestPrice + offset * openTrades[i].entryATR;
|
||||||
if(newSL < t.slPrice) t.slPrice = newSL;
|
if(newSL < openTrades[i].slPrice) openTrades[i].slPrice = newSL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trade da chiudere per inversione di segnale (ritorna array di ticket)
|
// Trade da chiudere per inversione di segnale (ritorna array di ticket)
|
||||||
void GetTradesToClose(int &closeTickets[], double currentZ, double minZ) {
|
void GetTradesToClose(int &closeTickets[], double currentZ, double minZ) {
|
||||||
|
|||||||
Reference in New Issue
Block a user