style: normalize indentation in Orchestrator.mqh via clang-format

Whitespace-only: consistent 3-space indentation throughout (was a mix of
3/4/5/6.. spaces). Repo conventions preserved: for(/if( spacing, access
labels, attached braces. Adds .clang-format so the style is reproducible
(run: clang-format -i --style=file <file>).

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Pietro Giacobazzi
2026-06-14 18:21:44 +00:00
co-authored by Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
parent a8b4a7d3ff
commit bb670836e1
2 changed files with 1327 additions and 1259 deletions
+15
View File
@@ -0,0 +1,15 @@
BasedOnStyle: LLVM
IndentWidth: 3
TabWidth: 3
UseTab: Never
ColumnLimit: 0
BreakBeforeBraces: Attach
AllowShortFunctionsOnASingleLine: All
AllowShortBlocksOnASingleLine: Always
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: true
SortIncludes: false
SpaceBeforeParens: Never
IndentCaseLabels: true
AccessModifierOffset: -3
PointerAlignment: Right
+195 -142
View File
@@ -233,32 +233,36 @@ public:
int OpenTradeCount() const { int OpenTradeCount() const {
int c = 0; int c = 0;
for(int i=0; i<maxOpenTrades; i++) if(openTrades[i].active) c++; for(int i = 0; i < maxOpenTrades; i++)
if(openTrades[i].active) c++;
return c; return c;
} }
int OpenTradeCount(bool isBuy) const { int OpenTradeCount(bool isBuy) const {
int c = 0; int c = 0;
for(int i=0; i<maxOpenTrades; i++) if(openTrades[i].active && openTrades[i].isBuy == isBuy) c++; for(int i = 0; i < maxOpenTrades; i++)
if(openTrades[i].active && openTrades[i].isBuy == isBuy) c++;
return c; return c;
} }
bool HasOpenTrade() const { return OpenTradeCount() > 0; } bool HasOpenTrade() const { return OpenTradeCount() > 0; }
int OpenTicket() const { int OpenTicket() const {
for(int i=0; i<maxOpenTrades; i++) if(openTrades[i].active) return openTrades[i].ticket; for(int i = 0; i < maxOpenTrades; i++)
if(openTrades[i].active) return openTrades[i].ticket;
return -1; return -1;
} }
double EntryPrice() const { double EntryPrice() const {
for(int i=0; i<maxOpenTrades; i++) if(openTrades[i].active) return openTrades[i].entryPrice; for(int i = 0; i < maxOpenTrades; i++)
if(openTrades[i].active) return openTrades[i].entryPrice;
return 0; return 0;
} }
void ResetTradeState() { void ResetTradeState() {
for(int i=0; i<maxOpenTrades; i++) openTrades[i].active = false; for(int i = 0; i < maxOpenTrades; i++) openTrades[i].active = false;
} }
Orchestrator(double minZ=0.5, double wMin=0.05, double wAlpha=0.05, Orchestrator(double minZ = 0.5, double wMin = 0.05, double wAlpha = 0.05,
bool useNeural=false, string modelFile="", bool useNeural = false, string modelFile = "",
bool trainMode=false, int nnEpochs=100, bool trainMode = false, int nnEpochs = 100,
double nnLR=0.001, int nnHidden=6, double nnLR = 0.001, int nnHidden = 6,
double riskPerTrade=0.01, double riskTotal=0.05) { double riskPerTrade = 0.01, double riskTotal = 0.05) {
agentCount = 0; agentCount = 0;
combinedZ = 0; combinedZ = 0;
minActionableZ = minZ; minActionableZ = minZ;
@@ -273,9 +277,9 @@ public:
// Capacità iniziale: 1000 slot, cresce dinamicamente all'occorrenza // Capacità iniziale: 1000 slot, cresce dinamicamente all'occorrenza
maxOpenTrades = 1000; maxOpenTrades = 1000;
ArrayResize(openTrades, maxOpenTrades); ArrayResize(openTrades, maxOpenTrades);
for(int i=0; i<maxOpenTrades; i++) openTrades[i].active = false; for(int i = 0; i < maxOpenTrades; i++) openTrades[i].active = false;
for(int i=0; i<MAX_AGENTS; i++) InitCorrelation(i); for(int i = 0; i < MAX_AGENTS; i++) InitCorrelation(i);
// Self-evaluation init // Self-evaluation init
rollingIdx = 0; rollingIdx = 0;
@@ -288,8 +292,8 @@ public:
convergeCount = 0; convergeCount = 0;
isConverged = false; isConverged = false;
maxDeltaRho = 0; maxDeltaRho = 0;
for(int i=0; i<MAX_AGENTS; i++) prevCorr[i] = 0; for(int i = 0; i < MAX_AGENTS; i++) prevCorr[i] = 0;
for(int i=0; i<ROLLING_TRADES; i++) rollingReturns[i] = 0; for(int i = 0; i < ROLLING_TRADES; i++) rollingReturns[i] = 0;
// Neural network init // Neural network init
m_useNeural = useNeural; m_useNeural = useNeural;
@@ -335,7 +339,7 @@ public:
} }
void ReleaseAgents() { void ReleaseAgents() {
for(int i=0; i<agentCount; i++) { for(int i = 0; i < agentCount; i++) {
if(agents[i]) { if(agents[i]) {
agents[i].Release(); agents[i].Release();
delete agents[i]; delete agents[i];
@@ -366,20 +370,28 @@ public:
} }
void InitAgents(string symbol, ENUM_TIMEFRAMES tf) { void InitAgents(string symbol, ENUM_TIMEFRAMES tf) {
for(int i=0; i<agentCount; i++) for(int i = 0; i < agentCount; i++)
agents[i].Init(symbol, tf); agents[i].Init(symbol, tf);
} }
int TotalAgents() const { return agentCount; } int TotalAgents() const { return agentCount; }
double Analyze(const MarketData &data) { double Analyze(const MarketData &data) {
if(agentCount == 0) { combinedZ = 0; return 0; } if(agentCount == 0) {
combinedZ = 0;
return 0;
}
double zs[MAX_AGENTS], ws[MAX_AGENTS], corrSign[MAX_AGENTS]; double zs[MAX_AGENTS], ws[MAX_AGENTS], corrSign[MAX_AGENTS];
// Fase 1: Analisi individuale // Fase 1: Analisi individuale
for(int i=0; i<agentCount; i++) { for(int i = 0; i < agentCount; i++) {
if(!agents[i].enabled) { zs[i] = 0; ws[i] = 0; corrSign[i] = 1.0; continue; } if(!agents[i].enabled) {
zs[i] = 0;
ws[i] = 0;
corrSign[i] = 1.0;
continue;
}
zs[i] = agents[i].Analyze(data); zs[i] = agents[i].Analyze(data);
double rho = GetCorrelation(i); double rho = GetCorrelation(i);
// Competenza = |correlazione| segnale/ritorni (con floor weightMin, così // Competenza = |correlazione| segnale/ritorni (con floor weightMin, così
@@ -390,32 +402,36 @@ public:
} }
// Fase 2: Interazione tra agenti (es. RegimeDetector aggiorna shared context) // Fase 2: Interazione tra agenti (es. RegimeDetector aggiorna shared context)
for(int i=0; i<agentCount; i++) { for(int i = 0; i < agentCount; i++) {
if(agents[i].enabled) agents[i].Interact(agents, agentCount); if(agents[i].enabled) agents[i].Interact(agents, agentCount);
} }
// Dopo Interact, aggiorna zs[] con lastZScore (alcuni agenti come PatternHunter // Dopo Interact, aggiorna zs[] con lastZScore (alcuni agenti come PatternHunter
// generano il segnale SOLO in Interact, non in Analyze) // generano il segnale SOLO in Interact, non in Analyze)
for(int i=0; i<agentCount; i++) { for(int i = 0; i < agentCount; i++) {
if(agents[i].enabled) zs[i] = agents[i].lastZScore; if(agents[i].enabled) zs[i] = agents[i].lastZScore;
} }
// Fase 3: Neural o Softmax Gating // Fase 3: Neural o Softmax Gating
// Se la rete neurale è attiva e addestrata, usa forward pass // Se la rete neurale è attiva e addestrata, usa forward pass
bool neuralReady = m_useNeural && m_neuralNet != NULL bool neuralReady = m_useNeural && m_neuralNet != NULL && m_neuralNet.IsInitialized() && m_neuralNet.EpochsTrained() > 0;
&& m_neuralNet.IsInitialized()
&& m_neuralNet.EpochsTrained() > 0;
if(neuralReady) { if(neuralReady) {
// Estrai feature vector: [z_Hurst, z_ADX, z_MA, z_Mom, z_Consensus, z_Pattern, agreement, trendStrength] // Estrai feature vector: [z_Hurst, z_ADX, z_MA, z_Mom, z_Consensus, z_Pattern, agreement, trendStrength]
vector nnInput(NN_FEATURES); vector nnInput(NN_FEATURES);
for(int f = 0; f < NN_FEATURES; f++) nnInput[f] = 0.0; for(int f = 0; f < NN_FEATURES; f++) nnInput[f] = 0.0;
for(int i=0; i<agentCount; i++) { for(int i = 0; i < agentCount; i++) {
if(agents[i].name == "Hurst") nnInput[0] = agents[i].lastZScore; if(agents[i].name == "Hurst")
else if(agents[i].name == "ADX") nnInput[1] = agents[i].lastZScore; nnInput[0] = agents[i].lastZScore;
else if(agents[i].name == "MA") nnInput[2] = agents[i].lastZScore; else if(agents[i].name == "ADX")
else if(agents[i].name == "Momentum") nnInput[3] = agents[i].lastZScore; nnInput[1] = agents[i].lastZScore;
else if(agents[i].name == "Consensus") nnInput[4] = agents[i].lastZScore; else if(agents[i].name == "MA")
else if(agents[i].name == "Hunter") nnInput[5] = agents[i].lastZScore; nnInput[2] = agents[i].lastZScore;
else if(agents[i].name == "Momentum")
nnInput[3] = agents[i].lastZScore;
else if(agents[i].name == "Consensus")
nnInput[4] = agents[i].lastZScore;
else if(agents[i].name == "Hunter")
nnInput[5] = agents[i].lastZScore;
} }
nnInput[6] = SHARED_regimeAgreement; nnInput[6] = SHARED_regimeAgreement;
nnInput[7] = SHARED_trendStrength; nnInput[7] = SHARED_trendStrength;
@@ -430,14 +446,14 @@ public:
// (mixing più uniforme, evita di sovra-fidarsi di un singolo agente). // (mixing più uniforme, evita di sovra-fidarsi di un singolo agente).
double wMean = 0; double wMean = 0;
int wCount = 0; int wCount = 0;
for(int i=0; i<agentCount; i++) { for(int i = 0; i < agentCount; i++) {
if(!agents[i].enabled) continue; if(!agents[i].enabled) continue;
wMean += ws[i]; wMean += ws[i];
wCount++; wCount++;
} }
if(wCount > 0) wMean /= wCount; if(wCount > 0) wMean /= wCount;
double wVar = 0; double wVar = 0;
for(int i=0; i<agentCount; i++) { for(int i = 0; i < agentCount; i++) {
if(!agents[i].enabled) continue; if(!agents[i].enabled) continue;
wVar += (ws[i] - wMean) * (ws[i] - wMean); wVar += (ws[i] - wMean) * (ws[i] - wMean);
} }
@@ -446,14 +462,14 @@ public:
double safeTemp = MathMax(temp, DATA_EPS(temp) * 10.0); // evita overflow di MathExp double safeTemp = MathMax(temp, DATA_EPS(temp) * 10.0); // evita overflow di MathExp
double sumExp = 0; double sumExp = 0;
for(int i=0; i<agentCount; i++) { for(int i = 0; i < agentCount; i++) {
if(!agents[i].enabled) continue; if(!agents[i].enabled) continue;
sumExp += MathExp(ws[i] / safeTemp); sumExp += MathExp(ws[i] / safeTemp);
} }
combinedZ = 0; combinedZ = 0;
double epsExp = DATA_EPS((double)wCount); double epsExp = DATA_EPS((double)wCount);
for(int i=0; i<agentCount; i++) { for(int i = 0; i < agentCount; i++) {
if(!agents[i].enabled) continue; if(!agents[i].enabled) continue;
double softmaxW = (sumExp > epsExp) ? MathExp(ws[i] / safeTemp) / sumExp : 1.0 / MathMax(1, wCount); double softmaxW = (sumExp > epsExp) ? MathExp(ws[i] / safeTemp) / sumExp : 1.0 / MathMax(1, wCount);
// Segnale sign-corretto: agenti anti-correlati contribuiscono invertiti. // Segnale sign-corretto: agenti anti-correlati contribuiscono invertiti.
@@ -504,8 +520,11 @@ public:
EnsureTradeCapacity(); EnsureTradeCapacity();
// Trova slot libero // Trova slot libero
int idx = -1; int idx = -1;
for(int i=0; i<maxOpenTrades; i++) { for(int i = 0; i < maxOpenTrades; i++) {
if(!openTrades[i].active) { idx = i; break; } if(!openTrades[i].active) {
idx = i;
break;
}
} }
if(idx < 0) { // non dovrebbe mai succedere dopo EnsureTradeCapacity if(idx < 0) { // non dovrebbe mai succedere dopo EnsureTradeCapacity
Print("ERROR: slot non disponibile nonostante capacity expansion"); Print("ERROR: slot non disponibile nonostante capacity expansion");
@@ -525,18 +544,24 @@ public:
openTrades[idx].mfeATR = 0; openTrades[idx].mfeATR = 0;
openTrades[idx].active = true; openTrades[idx].active = true;
for(int i=0; i<agentCount; i++) for(int i = 0; i < agentCount; i++)
openTrades[idx].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++) openTrades[idx].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") openTrades[idx].entryFeatures[0] = agents[i].lastZScore; if(agents[i].name == "Hurst")
else if(agents[i].name == "ADX") openTrades[idx].entryFeatures[1] = agents[i].lastZScore; openTrades[idx].entryFeatures[0] = agents[i].lastZScore;
else if(agents[i].name == "MA") openTrades[idx].entryFeatures[2] = agents[i].lastZScore; else if(agents[i].name == "ADX")
else if(agents[i].name == "Momentum") openTrades[idx].entryFeatures[3] = agents[i].lastZScore; openTrades[idx].entryFeatures[1] = agents[i].lastZScore;
else if(agents[i].name == "Consensus") openTrades[idx].entryFeatures[4] = agents[i].lastZScore; else if(agents[i].name == "MA")
else if(agents[i].name == "Hunter") openTrades[idx].entryFeatures[5] = agents[i].lastZScore; 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;
} }
openTrades[idx].entryFeatures[6] = SHARED_regimeAgreement; openTrades[idx].entryFeatures[6] = SHARED_regimeAgreement;
openTrades[idx].entryFeatures[7] = SHARED_trendStrength; openTrades[idx].entryFeatures[7] = SHARED_trendStrength;
@@ -586,7 +611,7 @@ public:
d.confidence = MathAbs(combinedZ); d.confidence = MathAbs(combinedZ);
d.minZ = minZ; d.minZ = minZ;
if(action == "SIGNAL" || action == "ENTRY") { if(action == "SIGNAL" || action == "ENTRY") {
for(int i=0; i<agentCount; i++) { for(int i = 0; i < agentCount; i++) {
if(agents[i].enabled && MathAbs(agents[i].lastZScore) > 0.1) { if(agents[i].enabled && MathAbs(agents[i].lastZScore) > 0.1) {
if((agents[i].lastZScore > 0) == (dir > 0)) d.agreeingCount++; if((agents[i].lastZScore > 0) == (dir > 0)) d.agreeingCount++;
} }
@@ -596,11 +621,14 @@ public:
decisionCount++; decisionCount++;
} }
void OnTradeClose(int ticket, double closePrice, string exitReason = "MANUAL") { void OnTradeClose(int ticket, double closePrice, string exitReason = "MANUAL") {
// Trova il trade nell'array // Trova il trade nell'array
int idx = -1; int idx = -1;
for(int i=0; i<maxOpenTrades; i++) { for(int i = 0; i < maxOpenTrades; i++) {
if(openTrades[i].active && openTrades[i].ticket == ticket) { idx = i; break; } if(openTrades[i].active && openTrades[i].ticket == ticket) {
idx = i;
break;
}
} }
if(idx < 0) return; if(idx < 0) return;
@@ -644,10 +672,10 @@ void OnTradeClose(int ticket, double closePrice, string exitReason = "MANUAL") {
double sigThr = combinedZStats.Ready() double sigThr = combinedZStats.Ready()
? combinedZStats.Std() / MathSqrt(MathMax(1, agentCount)) ? combinedZStats.Std() / MathSqrt(MathMax(1, agentCount))
: 1.0 / MathSqrt(MathMax(1, agentCount)); : 1.0 / MathSqrt(MathMax(1, agentCount));
for(int i=0; i<agentCount; i++) { for(int i = 0; i < agentCount; i++) {
if(MathAbs(openTrades[idx].entryZScores[i]) < sigThr) continue; if(MathAbs(openTrades[idx].entryZScores[i]) < sigThr) continue;
UpdateCorrelation(i, openTrades[idx].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);
@@ -673,15 +701,21 @@ UpdateCorrelation(i, openTrades[idx].entryZScores[i], actualReturnZ);
double target[NN_TARGETS]; double target[NN_TARGETS];
for(int f = 0; f < NN_FEATURES; f++) features[f] = openTrades[idx].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 = openTrades[idx].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)
else target[2] = 1; target[0] = 1;
else
target[2] = 1;
} else { } else {
if(tradeDir == 1) target[2] = 1; if(tradeDir == 1)
else target[0] = 1; target[2] = 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ù
@@ -700,7 +734,7 @@ UpdateCorrelation(i, openTrades[idx].entryZScores[i], actualReturnZ);
} }
} }
UpdateHealth(actualReturn); UpdateHealth(actualReturn);
LogHealth(); LogHealth();
// Save completed trade record // Save completed trade record
@@ -732,14 +766,14 @@ UpdateHealth(actualReturn);
// Trova un trade per ticket // Trova un trade per ticket
int FindTrade(int ticket) const { int FindTrade(int ticket) const {
for(int i=0; i<maxOpenTrades; i++) for(int i = 0; i < maxOpenTrades; i++)
if(openTrades[i].active && openTrades[i].ticket == ticket) return i; if(openTrades[i].active && openTrades[i].ticket == ticket) return i;
return -1; return -1;
} }
// 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;
if(high > openTrades[i].highestPrice) openTrades[i].highestPrice = high; if(high > openTrades[i].highestPrice) openTrades[i].highestPrice = high;
if(low < openTrades[i].lowestPrice) openTrades[i].lowestPrice = low; if(low < openTrades[i].lowestPrice) openTrades[i].lowestPrice = low;
@@ -749,7 +783,7 @@ UpdateHealth(actualReturn);
// 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;
double profitATR = openTrades[i].isBuy double profitATR = openTrades[i].isBuy
@@ -774,7 +808,7 @@ UpdateHealth(actualReturn);
// 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) {
ArrayResize(closeTickets, 0); ArrayResize(closeTickets, 0);
for(int i=0; i<maxOpenTrades; i++) { for(int i = 0; i < maxOpenTrades; i++) {
if(!openTrades[i].active) continue; if(!openTrades[i].active) continue;
bool shouldClose = false; bool shouldClose = false;
// Chiudi buy se segnale fortemente ribassista // Chiudi buy se segnale fortemente ribassista
@@ -820,14 +854,14 @@ UpdateHealth(actualReturn);
int MaxTradeSlots() const { return maxOpenTrades; } int MaxTradeSlots() const { return maxOpenTrades; }
bool IsBuyTrade(int ticket) const { bool IsBuyTrade(int ticket) const {
for(int i=0; i<maxOpenTrades; i++) for(int i = 0; i < maxOpenTrades; i++)
if(openTrades[i].active && openTrades[i].ticket == ticket) if(openTrades[i].active && openTrades[i].ticket == ticket)
return openTrades[i].isBuy; return openTrades[i].isBuy;
return true; // default: buy return true; // default: buy
} }
double GetTradeSL(int ticket) const { double GetTradeSL(int ticket) const {
for(int i=0; i<maxOpenTrades; i++) for(int i = 0; i < maxOpenTrades; i++)
if(openTrades[i].active && openTrades[i].ticket == ticket) if(openTrades[i].active && openTrades[i].ticket == ticket)
return openTrades[i].slPrice; return openTrades[i].slPrice;
return -1; return -1;
@@ -836,7 +870,7 @@ UpdateHealth(actualReturn);
// Ritorna il ticket dell'n-esimo trade attivo (per iterazione esterna) // Ritorna il ticket dell'n-esimo trade attivo (per iterazione esterna)
int GetTrackedTicket(int nth) const { int GetTrackedTicket(int nth) const {
int count = 0; int count = 0;
for(int i=0; i<maxOpenTrades; i++) { for(int i = 0; i < maxOpenTrades; i++) {
if(openTrades[i].active) { if(openTrades[i].active) {
if(count == nth) return openTrades[i].ticket; if(count == nth) return openTrades[i].ticket;
count++; count++;
@@ -845,7 +879,7 @@ UpdateHealth(actualReturn);
return -1; return -1;
} }
FinalSignal GetFinalSignal(double overrideMinZ=0) { FinalSignal GetFinalSignal(double overrideMinZ = 0) {
double thr = (overrideMinZ > 0) ? overrideMinZ : AdaptiveMinZ(); double thr = (overrideMinZ > 0) ? overrideMinZ : AdaptiveMinZ();
int dir = 0; int dir = 0;
if(combinedZ > thr) dir = 1; if(combinedZ > thr) dir = 1;
@@ -859,7 +893,7 @@ UpdateHealth(actualReturn);
double sigThr = combinedZStats.Ready() double sigThr = combinedZStats.Ready()
? combinedZStats.Std() / MathSqrt(MathMax(1, agentCount)) ? combinedZStats.Std() / MathSqrt(MathMax(1, agentCount))
: 1.0 / MathSqrt(MathMax(1, agentCount)); : 1.0 / MathSqrt(MathMax(1, agentCount));
for(int i=0; i<agentCount; i++) { for(int i = 0; i < agentCount; i++) {
if(!agents[i].enabled) continue; if(!agents[i].enabled) continue;
if(MathAbs(agents[i].lastZScore) > sigThr) { if(MathAbs(agents[i].lastZScore) > sigThr) {
int agentDir = (agents[i].lastZScore > 0) ? 1 : -1; int agentDir = (agents[i].lastZScore > 0) ? 1 : -1;
@@ -876,7 +910,7 @@ UpdateHealth(actualReturn);
void PrintAgentLearningSummary() const { void PrintAgentLearningSummary() const {
Print("=== Agent Learning Summary ==="); Print("=== Agent Learning Summary ===");
for(int i=0; i<agentCount; i++) { for(int i = 0; i < agentCount; i++) {
string name = agents[i].name; string name = agents[i].name;
double bias = agents[i].predictionError.Mean(); double bias = agents[i].predictionError.Mean();
double biasN = agents[i].predictionError.Count(); double biasN = agents[i].predictionError.Count();
@@ -892,7 +926,7 @@ UpdateHealth(actualReturn);
void PrintAgentStatus() const { void PrintAgentStatus() const {
Print("=== Orchestrator Status ==="); Print("=== Orchestrator Status ===");
Print("combinedZ: ", StringFormat("%+.4f", combinedZ)); Print("combinedZ: ", StringFormat("%+.4f", combinedZ));
for(int i=0; i<agentCount; i++) { for(int i = 0; i < agentCount; i++) {
Print(" ", agents[i].SignalInfo(), Print(" ", agents[i].SignalInfo(),
" | ρ=", StringFormat("%+.3f", GetCorrelation(i)), " | ρ=", StringFormat("%+.3f", GetCorrelation(i)),
" | w=", StringFormat("%.3f", agents[i].weight)); " | w=", StringFormat("%.3f", agents[i].weight));
@@ -903,7 +937,7 @@ UpdateHealth(actualReturn);
} }
void Reset() { void Reset() {
for(int i=0; i<agentCount; i++) { for(int i = 0; i < agentCount; i++) {
agents[i].Reset(); agents[i].Reset();
InitCorrelation(i); InitCorrelation(i);
} }
@@ -911,7 +945,7 @@ UpdateHealth(actualReturn);
combinedZ = 0; combinedZ = 0;
if(m_trainBuffer) m_trainBuffer.Clear(); if(m_trainBuffer) m_trainBuffer.Clear();
for(int i=0; i<maxOpenTrades; i++) openTrades[i].active = false; for(int i = 0; i < maxOpenTrades; i++) openTrades[i].active = false;
maeStats.Reset(); maeStats.Reset();
mfeStats.Reset(); mfeStats.Reset();
maeWinStats.Reset(); maeWinStats.Reset();
@@ -926,8 +960,8 @@ UpdateHealth(actualReturn);
convergeCount = 0; convergeCount = 0;
isConverged = false; isConverged = false;
maxDeltaRho = 0; maxDeltaRho = 0;
for(int i=0; i<MAX_AGENTS; i++) prevCorr[i] = 0; for(int i = 0; i < MAX_AGENTS; i++) prevCorr[i] = 0;
for(int i=0; i<ROLLING_TRADES; i++) rollingReturns[i] = 0; for(int i = 0; i < ROLLING_TRADES; i++) rollingReturns[i] = 0;
histIdx = 0; histIdx = 0;
histCount = 0; histCount = 0;
@@ -952,7 +986,7 @@ UpdateHealth(actualReturn);
// Rolling Sharpe (corrMinSamples = numero minimo per una correlazione stabile) // Rolling Sharpe (corrMinSamples = numero minimo per una correlazione stabile)
if(rollingCount >= corrMinSamples) { if(rollingCount >= corrMinSamples) {
double sum = 0, sumSq = 0; double sum = 0, sumSq = 0;
for(int i=0; i<rollingCount; i++) { for(int i = 0; i < rollingCount; i++) {
sum += rollingReturns[i]; sum += rollingReturns[i];
sumSq += rollingReturns[i] * rollingReturns[i]; sumSq += rollingReturns[i] * rollingReturns[i];
} }
@@ -969,8 +1003,11 @@ UpdateHealth(actualReturn);
bool allHaveSamples = true; bool allHaveSamples = true;
maxDeltaRho = 0; maxDeltaRho = 0;
for(int i=0; i<agentCount; i++) { for(int i = 0; i < agentCount; i++) {
if(corrCount[i] < corrMinSamples) { allHaveSamples = false; break; } if(corrCount[i] < corrMinSamples) {
allHaveSamples = false;
break;
}
double rho = GetCorrelation(i); double rho = GetCorrelation(i);
double delta = MathAbs(rho - prevCorr[i]); double delta = MathAbs(rho - prevCorr[i]);
if(delta > maxDeltaRho) maxDeltaRho = delta; if(delta > maxDeltaRho) maxDeltaRho = delta;
@@ -1007,8 +1044,7 @@ UpdateHealth(actualReturn);
// z_0.95 ≈ invNormalCDF(0.95) tramite approssimazione di Abramowitz & Stegun 26.2.23 // z_0.95 ≈ invNormalCDF(0.95) tramite approssimazione di Abramowitz & Stegun 26.2.23
double p05 = 0.95; double p05 = 0.95;
double t = MathSqrt(-2.0 * MathLog(1.0 - p05)); double t = MathSqrt(-2.0 * MathLog(1.0 - p05));
double z095 = t - (2.515517 + 0.802853*t + 0.010328*t*t) double z095 = t - (2.515517 + 0.802853 * t + 0.010328 * t * t) / (1.0 + 1.432788 * t + 0.189269 * t * t + 0.001308 * t * t * t);
/ (1.0 + 1.432788*t + 0.189269*t*t + 0.001308*t*t*t);
if(sharpeZ > z095) if(sharpeZ > z095)
Print(" ✓ Sharpe significativamente positivo (z=", StringFormat("%.2f", sharpeZ), ")"); Print(" ✓ Sharpe significativamente positivo (z=", StringFormat("%.2f", sharpeZ), ")");
} }
@@ -1018,7 +1054,7 @@ UpdateHealth(actualReturn);
void LogBarHistory(datetime time) { void LogBarHistory(datetime time) {
history[histIdx].time = time; history[histIdx].time = time;
history[histIdx].combinedZ = combinedZ; history[histIdx].combinedZ = combinedZ;
for(int i=0; i<agentCount; i++) { for(int i = 0; i < agentCount; i++) {
history[histIdx].z[i] = agents[i].lastZScore; history[histIdx].z[i] = agents[i].lastZScore;
agentHistory[histIdx][i].lastZScore = agents[i].lastZScore; agentHistory[histIdx][i].lastZScore = agents[i].lastZScore;
agentHistory[histIdx][i].weight = agents[i].weight; agentHistory[histIdx][i].weight = agents[i].weight;
@@ -1056,7 +1092,7 @@ UpdateHealth(actualReturn);
// Somma del rischio (in valuta conto) di tutte le posizioni aperte // Somma del rischio (in valuta conto) di tutte le posizioni aperte
double TotalRiskUsed() const { double TotalRiskUsed() const {
double total = 0; double total = 0;
for(int i=0; i<maxOpenTrades; i++) for(int i = 0; i < maxOpenTrades; i++)
if(openTrades[i].active) total += openTrades[i].riskAmount; if(openTrades[i].active) total += openTrades[i].riskAmount;
return total; return total;
} }
@@ -1078,7 +1114,10 @@ UpdateHealth(actualReturn);
double maxTotalRisk = bal * m_riskTotal; double maxTotalRisk = bal * m_riskTotal;
double usedRisk = TotalRiskUsed(); double usedRisk = TotalRiskUsed();
double remainingRisk = maxTotalRisk - usedRisk; double remainingRisk = maxTotalRisk - usedRisk;
if(remainingRisk <= 0) { Print(" Risk budget esaurito (", StringFormat("%.2f", usedRisk), "/", StringFormat("%.2f", maxTotalRisk), ")"); return 0; } if(remainingRisk <= 0) {
Print(" Risk budget esaurito (", StringFormat("%.2f", usedRisk), "/", StringFormat("%.2f", maxTotalRisk), ")");
return 0;
}
riskAmount = MathMin(riskAmount, remainingRisk); riskAmount = MathMin(riskAmount, remainingRisk);
// Costo in valuta conto per 1 lotto a questa distanza SL // Costo in valuta conto per 1 lotto a questa distanza SL
@@ -1107,25 +1146,27 @@ UpdateHealth(actualReturn);
int n = histCount; int n = histCount;
if(n < corrMinSamples) return 0; if(n < corrMinSamples) return 0;
int lag = 1; int lag = 1;
double sum=0, sumSq=0, sumShift=0, sumSqShift=0, sumCov=0; double sum = 0, sumSq = 0, sumShift = 0, sumSqShift = 0, sumCov = 0;
// Usa fino a n/2 per bilanciare stabilità e reattività, minimo corrMinSamples // Usa fino a n/2 per bilanciare stabilità e reattività, minimo corrMinSamples
int cnt = MathMin(n, MathMax(corrMinSamples, n / 2)); int cnt = MathMin(n, MathMax(corrMinSamples, n / 2));
for(int i=0; i<cnt-lag; i++) { for(int i = 0; i < cnt - lag; i++) {
int ii = (histIdx - 1 - i + MAX_HISTORY) % MAX_HISTORY; int ii = (histIdx - 1 - i + MAX_HISTORY) % MAX_HISTORY;
int jj = (ii - lag + MAX_HISTORY) % MAX_HISTORY; int jj = (ii - lag + MAX_HISTORY) % MAX_HISTORY;
double x = history[ii].combinedZ; double x = history[ii].combinedZ;
double y = history[jj].combinedZ; double y = history[jj].combinedZ;
sum += x; sumSq += x*x; sum += x;
sumShift += y; sumSqShift += y*y; sumSq += x * x;
sumCov += x*y; sumShift += y;
sumSqShift += y * y;
sumCov += x * y;
} }
double mean = sum/cnt, meanS = sumShift/cnt; double mean = sum / cnt, meanS = sumShift / cnt;
double var = sumSq/cnt - mean*mean; double var = sumSq / cnt - mean * mean;
double varS = sumSqShift/cnt - meanS*meanS; double varS = sumSqShift / cnt - meanS * meanS;
double cov = sumCov/cnt - mean*meanS; double cov = sumCov / cnt - mean * meanS;
double denom = MathSqrt(var*varS); double denom = MathSqrt(var * varS);
double epsDenom = DATA_EPS(MathSqrt(MathMax(0, var) + MathMax(0, varS))); double epsDenom = DATA_EPS(MathSqrt(MathMax(0, var) + MathMax(0, varS)));
return (denom > epsDenom) ? cov/denom : 0; return (denom > epsDenom) ? cov / denom : 0;
} }
double TradeSharpe() const { double TradeSharpe() const {
@@ -1188,8 +1229,10 @@ UpdateHealth(actualReturn);
string fn = (m_modelFilename != "") ? m_modelFilename string fn = (m_modelFilename != "") ? m_modelFilename
: "TR_Agent_NN_" + Symbol() + "_" + EnumToString(Period()) + "_" + m_runTimestamp + ".dat"; : "TR_Agent_NN_" + Symbol() + "_" + EnumToString(Period()) + "_" + m_runTimestamp + ".dat";
bool ok = m_neuralNet.Save(fn); bool ok = m_neuralNet.Save(fn);
if(ok) Print("NN model saved: ", fn); if(ok)
else Print("NN model save FAILED: ", fn); Print("NN model saved: ", fn);
else
Print("NN model save FAILED: ", fn);
return ok; return ok;
} }
@@ -1209,9 +1252,7 @@ UpdateHealth(actualReturn);
} }
bool IsNeuralReady() const { bool IsNeuralReady() const {
return m_useNeural && m_neuralNet != NULL return m_useNeural && m_neuralNet != NULL && m_neuralNet.IsInitialized() && m_neuralNet.EpochsTrained() > 0;
&& m_neuralNet.IsInitialized()
&& m_neuralNet.EpochsTrained() > 0;
} }
string NeuralInfo() const { string NeuralInfo() const {
@@ -1222,18 +1263,15 @@ UpdateHealth(actualReturn);
// Salva summary CSV con learning stats di ogni agente // Salva summary CSV con learning stats di ogni agente
void SaveAgentLearningCsv() const { void SaveAgentLearningCsv() const {
string fn = "AgentLearning_" + Symbol() + "_" + EnumToString(Period()) + "_" + m_runTimestamp + ".csv"; string fn = "AgentLearning_" + Symbol() + "_" + EnumToString(Period()) + "_" + m_runTimestamp + ".csv";
int fh = FileOpen(fn, FILE_TXT|FILE_WRITE|FILE_COMMON); int fh = FileOpen(fn, FILE_TXT | FILE_WRITE | FILE_COMMON);
if(fh == INVALID_HANDLE) return; if(fh == INVALID_HANDLE) return;
FileWriteString(fh, "agent,bias,bias_n,rho_learn,rho_learn_n,weight\n"); FileWriteString(fh, "agent,bias,bias_n,rho_learn,rho_learn_n,weight\n");
for(int i=0; i<agentCount; i++) { for(int i = 0; i < agentCount; i++) {
double bias = agents[i].predictionError.Mean(); double bias = agents[i].predictionError.Mean();
int biasN = agents[i].predictionError.Count(); int biasN = agents[i].predictionError.Count();
double rho = agents[i].predCorr.Ready() ? agents[i].predCorr.Correlation() : 0; double rho = agents[i].predCorr.Ready() ? agents[i].predCorr.Correlation() : 0;
int rhoN = agents[i].predCorr.Count(); int rhoN = agents[i].predCorr.Count();
FileWriteString(fh, agents[i].name + "," FileWriteString(fh, agents[i].name + "," + StringFormat("%+.6f", bias) + "," + (string)biasN + "," + StringFormat("%+.6f", rho) + "," + (string)rhoN + "," + StringFormat("%.6f", agents[i].weight) + "\r\n");
+ StringFormat("%+.6f", bias) + "," + (string)biasN + ","
+ StringFormat("%+.6f", rho) + "," + (string)rhoN + ","
+ StringFormat("%.6f", agents[i].weight) + "\r\n");
} }
FileClose(fh); FileClose(fh);
Print("Agent learning CSV saved: ", fn); Print("Agent learning CSV saved: ", fn);
@@ -1246,7 +1284,7 @@ UpdateHealth(actualReturn);
void SaveState(string symbol, ENUM_TIMEFRAMES tf) const { void SaveState(string symbol, ENUM_TIMEFRAMES tf) const {
string fn = ModelFilename(symbol, tf); string fn = ModelFilename(symbol, tf);
int fh = FileOpen(fn, FILE_WRITE|FILE_BIN|FILE_COMMON); int fh = FileOpen(fn, FILE_WRITE | FILE_BIN | FILE_COMMON);
if(fh == INVALID_HANDLE) { if(fh == INVALID_HANDLE) {
Print("Save: impossibile creare ", fn, " errore ", GetLastError()); Print("Save: impossibile creare ", fn, " errore ", GetLastError());
return; return;
@@ -1258,11 +1296,11 @@ UpdateHealth(actualReturn);
FileWriteInteger(fh, agentCount); FileWriteInteger(fh, agentCount);
// Agenti (RunningStats + extra) // Agenti (RunningStats + extra)
for(int i=0; i<agentCount; i++) for(int i = 0; i < agentCount; i++)
agents[i].Save(fh); agents[i].Save(fh);
// Correlazioni per agente // Correlazioni per agente
for(int i=0; i<agentCount; i++) { for(int i = 0; i < agentCount; i++) {
FileWriteDouble(fh, corrMeanX[i]); FileWriteDouble(fh, corrMeanX[i]);
FileWriteDouble(fh, corrMeanY[i]); FileWriteDouble(fh, corrMeanY[i]);
FileWriteDouble(fh, corrCov[i]); FileWriteDouble(fh, corrCov[i]);
@@ -1279,11 +1317,11 @@ UpdateHealth(actualReturn);
FileWriteInteger(fh, histIdx); FileWriteInteger(fh, histIdx);
int nHist = MathMin(histCount, MAX_HISTORY); int nHist = MathMin(histCount, MAX_HISTORY);
int start = (histCount >= MAX_HISTORY) ? histIdx : 0; // dal più vecchio int start = (histCount >= MAX_HISTORY) ? histIdx : 0; // dal più vecchio
for(int i=0; i<nHist; i++) { for(int i = 0; i < nHist; i++) {
int ii = (start + i) % MAX_HISTORY; int ii = (start + i) % MAX_HISTORY;
FileWriteInteger(fh, (int)history[ii].time); FileWriteInteger(fh, (int)history[ii].time);
FileWriteDouble(fh, history[ii].combinedZ); FileWriteDouble(fh, history[ii].combinedZ);
for(int j=0; j<agentCount; j++) for(int j = 0; j < agentCount; j++)
FileWriteDouble(fh, history[ii].z[j]); FileWriteDouble(fh, history[ii].z[j]);
} }
@@ -1313,7 +1351,7 @@ UpdateHealth(actualReturn);
return; return;
} }
int fh = FileOpen(fn, FILE_READ|FILE_BIN|FILE_COMMON); int fh = FileOpen(fn, FILE_READ | FILE_BIN | FILE_COMMON);
if(fh == INVALID_HANDLE) { if(fh == INVALID_HANDLE) {
Print("Load: impossibile aprire ", fn); Print("Load: impossibile aprire ", fn);
return; return;
@@ -1323,10 +1361,10 @@ UpdateHealth(actualReturn);
int savedCount = FileReadInteger(fh); int savedCount = FileReadInteger(fh);
int n = MathMin(savedCount, agentCount); int n = MathMin(savedCount, agentCount);
for(int i=0; i<n; i++) for(int i = 0; i < n; i++)
agents[i].Load(fh); agents[i].Load(fh);
for(int i=0; i<n; i++) { for(int i = 0; i < n; i++) {
corrMeanX[i] = FileReadDouble(fh); corrMeanX[i] = FileReadDouble(fh);
corrMeanY[i] = FileReadDouble(fh); corrMeanY[i] = FileReadDouble(fh);
corrCov[i] = FileReadDouble(fh); corrCov[i] = FileReadDouble(fh);
@@ -1342,12 +1380,12 @@ UpdateHealth(actualReturn);
int savedHist = FileReadInteger(fh); int savedHist = FileReadInteger(fh);
int savedIdx = FileReadInteger(fh); int savedIdx = FileReadInteger(fh);
int nHist = MathMin(savedHist, MAX_HISTORY); int nHist = MathMin(savedHist, MAX_HISTORY);
for(int i=0; i<nHist; i++) { for(int i = 0; i < nHist; i++) {
int ii = (savedHist >= MAX_HISTORY) ? (savedIdx + i) % MAX_HISTORY : i; int ii = (savedHist >= MAX_HISTORY) ? (savedIdx + i) % MAX_HISTORY : i;
if(ii < 0 || ii >= MAX_HISTORY) { ii = 0; } if(ii < 0 || ii >= MAX_HISTORY) { ii = 0; }
history[ii].time = (datetime)FileReadInteger(fh); history[ii].time = (datetime)FileReadInteger(fh);
history[ii].combinedZ = FileReadDouble(fh); history[ii].combinedZ = FileReadDouble(fh);
for(int j=0; j<agentCount && j<MAX_AGENTS; j++) for(int j = 0; j < agentCount && j < MAX_AGENTS; j++)
history[ii].z[j] = FileReadDouble(fh); history[ii].z[j] = FileReadDouble(fh);
} }
histCount = nHist; histCount = nHist;
@@ -1389,8 +1427,11 @@ UpdateHealth(actualReturn);
// Salva CSV con TUTTI i parametri derivati per analisi periodica // Salva CSV con TUTTI i parametri derivati per analisi periodica
void SaveAnalysisCSV(string symbol, ENUM_TIMEFRAMES tf) const { void SaveAnalysisCSV(string symbol, ENUM_TIMEFRAMES tf) const {
string fn = "TR_Agent_Analysis_" + symbol + "_" + EnumToString(tf) + "_" + m_runTimestamp + ".csv"; string fn = "TR_Agent_Analysis_" + symbol + "_" + EnumToString(tf) + "_" + m_runTimestamp + ".csv";
int fh = FileOpen(fn, FILE_TXT|FILE_WRITE|FILE_COMMON); int fh = FileOpen(fn, FILE_TXT | FILE_WRITE | FILE_COMMON);
if(fh == INVALID_HANDLE) { Print("SaveAnalysis: errore apertura ", fn); return; } if(fh == INVALID_HANDLE) {
Print("SaveAnalysis: errore apertura ", fn);
return;
}
// ===================== INTESTAZIONE ===================== // ===================== INTESTAZIONE =====================
FileWriteString(fh, "=== TR_Agent Analysis Report ===\r\n"); FileWriteString(fh, "=== TR_Agent Analysis Report ===\r\n");
@@ -1466,7 +1507,7 @@ UpdateHealth(actualReturn);
// ===================== AGENTI ===================== // ===================== AGENTI =====================
FileWriteString(fh, "=== Agent Details ===\r\n"); FileWriteString(fh, "=== Agent Details ===\r\n");
FileWriteString(fh, "Name,Weight,Rho,LastZ,Bias,BiasN,RhoLearn,RhoLearnN\r\n"); FileWriteString(fh, "Name,Weight,Rho,LastZ,Bias,BiasN,RhoLearn,RhoLearnN\r\n");
for(int i=0; i<agentCount; i++) { for(int i = 0; i < agentCount; i++) {
double rho = GetCorrelation(i); double rho = GetCorrelation(i);
double bias = agents[i].predictionError.Mean(); double bias = agents[i].predictionError.Mean();
double biasN = agents[i].predictionError.Count(); double biasN = agents[i].predictionError.Count();
@@ -1515,12 +1556,15 @@ UpdateHealth(actualReturn);
// ===================== SAVE BAR HISTORY CSV ===================== // ===================== SAVE BAR HISTORY CSV =====================
void SaveBarHistoryCSV(string symbol, ENUM_TIMEFRAMES tf) const { void SaveBarHistoryCSV(string symbol, ENUM_TIMEFRAMES tf) const {
string fn = "BarHistory_" + symbol + "_" + EnumToString(tf) + "_" + m_runTimestamp + ".csv"; string fn = "BarHistory_" + symbol + "_" + EnumToString(tf) + "_" + m_runTimestamp + ".csv";
int fh = FileOpen(fn, FILE_TXT|FILE_WRITE|FILE_COMMON); int fh = FileOpen(fn, FILE_TXT | FILE_WRITE | FILE_COMMON);
if(fh == INVALID_HANDLE) { Print("BarHistoryCSV: errore apertura ", fn); return; } if(fh == INVALID_HANDLE) {
Print("BarHistoryCSV: errore apertura ", fn);
return;
}
string header = "bar,time,combinedZ"; string header = "bar,time,combinedZ";
string agentNames[MAX_AGENTS]; string agentNames[MAX_AGENTS];
for(int i=0; i<agentCount; i++) { for(int i = 0; i < agentCount; i++) {
agentNames[i] = agents[i].name; agentNames[i] = agents[i].name;
header += "," + agentNames[i] + "_z"; header += "," + agentNames[i] + "_z";
} }
@@ -1529,10 +1573,10 @@ UpdateHealth(actualReturn);
int n = MathMin(histCount, MAX_HISTORY); int n = MathMin(histCount, MAX_HISTORY);
int start = (histCount >= MAX_HISTORY) ? histIdx : 0; int start = (histCount >= MAX_HISTORY) ? histIdx : 0;
for(int i=0; i<n; i++) { for(int i = 0; i < n; i++) {
int ii = (start + i) % MAX_HISTORY; int ii = (start + i) % MAX_HISTORY;
string line = (string)i + "," + TimeToString(history[ii].time) + "," + StringFormat("%+.6f", history[ii].combinedZ); string line = (string)i + "," + TimeToString(history[ii].time) + "," + StringFormat("%+.6f", history[ii].combinedZ);
for(int j=0; j<agentCount; j++) for(int j = 0; j < agentCount; j++)
line += "," + StringFormat("%+.6f", history[ii].z[j]); line += "," + StringFormat("%+.6f", history[ii].z[j]);
line += "," + StringFormat("%.4f", SHARED_regimeH); line += "," + StringFormat("%.4f", SHARED_regimeH);
line += "," + StringFormat("%.1f", SHARED_adxRaw); line += "," + StringFormat("%.1f", SHARED_adxRaw);
@@ -1549,21 +1593,24 @@ UpdateHealth(actualReturn);
// ===================== SAVE TRADE HISTORY CSV ===================== // ===================== SAVE TRADE HISTORY CSV =====================
void SaveTradeHistoryCSV(string symbol, ENUM_TIMEFRAMES tf) const { void SaveTradeHistoryCSV(string symbol, ENUM_TIMEFRAMES tf) const {
string fn = "TradeHistory_" + symbol + "_" + EnumToString(tf) + "_" + m_runTimestamp + ".csv"; string fn = "TradeHistory_" + symbol + "_" + EnumToString(tf) + "_" + m_runTimestamp + ".csv";
int fh = FileOpen(fn, FILE_TXT|FILE_WRITE|FILE_COMMON); int fh = FileOpen(fn, FILE_TXT | FILE_WRITE | FILE_COMMON);
if(fh == INVALID_HANDLE) { Print("TradeHistoryCSV: errore apertura ", fn); return; } if(fh == INVALID_HANDLE) {
Print("TradeHistoryCSV: errore apertura ", fn);
return;
}
string header = "ticket,isBuy,entryTime,closeTime,barsHeld,entryPrice,closePrice,entryATR,entryZ,slPrice,highestPrice,lowestPrice,maeATR,mfeATR,actualReturn,exitReason"; string header = "ticket,isBuy,entryTime,closeTime,barsHeld,entryPrice,closePrice,entryATR,entryZ,slPrice,highestPrice,lowestPrice,maeATR,mfeATR,actualReturn,exitReason";
string agentNames[MAX_AGENTS]; string agentNames[MAX_AGENTS];
for(int i=0; i<agentCount; i++) { for(int i = 0; i < agentCount; i++) {
agentNames[i] = agents[i].name; agentNames[i] = agents[i].name;
header += "," + agentNames[i] + "_entryZ"; header += "," + agentNames[i] + "_entryZ";
} }
string featLabels[NN_FEATURES] = {"Hurst","ADX","MA","Momentum","Consensus","Hunter","Agreement","TrendStr"}; string featLabels[NN_FEATURES] = {"Hurst", "ADX", "MA", "Momentum", "Consensus", "Hunter", "Agreement", "TrendStr"};
for(int f=0; f<NN_FEATURES; f++) header += ",feat_" + featLabels[f]; for(int f = 0; f < NN_FEATURES; f++) header += ",feat_" + featLabels[f];
FileWriteString(fh, header + "\r\n"); FileWriteString(fh, header + "\r\n");
// Completed trades // Completed trades
for(int t=0; t<completedTradeCount; t++) { for(int t = 0; t < completedTradeCount; t++) {
string line = (string)completedTrades[t].ticket; string line = (string)completedTrades[t].ticket;
line += "," + (string)(completedTrades[t].isBuy ? 1 : 0); line += "," + (string)(completedTrades[t].isBuy ? 1 : 0);
line += "," + TimeToString(completedTrades[t].entryTime); line += "," + TimeToString(completedTrades[t].entryTime);
@@ -1580,15 +1627,15 @@ UpdateHealth(actualReturn);
line += "," + StringFormat("%.4f", completedTrades[t].mfeATR); line += "," + StringFormat("%.4f", completedTrades[t].mfeATR);
line += "," + StringFormat("%+.4f", completedTrades[t].actualReturn); line += "," + StringFormat("%+.4f", completedTrades[t].actualReturn);
line += "," + completedTrades[t].exitReason; line += "," + completedTrades[t].exitReason;
for(int j=0; j<agentCount; j++) for(int j = 0; j < agentCount; j++)
line += "," + StringFormat("%+.4f", completedTrades[t].entryZScores[j]); line += "," + StringFormat("%+.4f", completedTrades[t].entryZScores[j]);
for(int f=0; f<NN_FEATURES; f++) for(int f = 0; f < NN_FEATURES; f++)
line += "," + StringFormat("%+.4f", completedTrades[t].entryFeatures[f]); line += "," + StringFormat("%+.4f", completedTrades[t].entryFeatures[f]);
FileWriteString(fh, line + "\r\n"); FileWriteString(fh, line + "\r\n");
} }
// Open trades (still active) // Open trades (still active)
for(int i=0; i<maxOpenTrades; i++) { for(int i = 0; i < maxOpenTrades; i++) {
if(!openTrades[i].active) continue; if(!openTrades[i].active) continue;
string line = (string)openTrades[i].ticket; string line = (string)openTrades[i].ticket;
line += "," + (string)(openTrades[i].isBuy ? 1 : 0); line += "," + (string)(openTrades[i].isBuy ? 1 : 0);
@@ -1604,9 +1651,9 @@ UpdateHealth(actualReturn);
line += "," + StringFormat("%.4f", openTrades[i].maeATR); line += "," + StringFormat("%.4f", openTrades[i].maeATR);
line += "," + StringFormat("%.4f", openTrades[i].mfeATR); line += "," + StringFormat("%.4f", openTrades[i].mfeATR);
line += ",,OPEN"; // no return, exit=OPEN line += ",,OPEN"; // no return, exit=OPEN
for(int j=0; j<agentCount; j++) for(int j = 0; j < agentCount; j++)
line += "," + StringFormat("%+.4f", openTrades[i].entryZScores[j]); line += "," + StringFormat("%+.4f", openTrades[i].entryZScores[j]);
for(int f=0; f<NN_FEATURES; f++) for(int f = 0; f < NN_FEATURES; f++)
line += "," + StringFormat("%+.4f", openTrades[i].entryFeatures[f]); line += "," + StringFormat("%+.4f", openTrades[i].entryFeatures[f]);
FileWriteString(fh, line + "\r\n"); FileWriteString(fh, line + "\r\n");
} }
@@ -1617,11 +1664,14 @@ UpdateHealth(actualReturn);
// ===================== SAVE AGENT INTERACTION CSV ===================== // ===================== SAVE AGENT INTERACTION CSV =====================
void SaveAgentInteractionCSV(string symbol, ENUM_TIMEFRAMES tf) const { void SaveAgentInteractionCSV(string symbol, ENUM_TIMEFRAMES tf) const {
string fn = "AgentInteraction_" + symbol + "_" + EnumToString(tf) + "_" + m_runTimestamp + ".csv"; string fn = "AgentInteraction_" + symbol + "_" + EnumToString(tf) + "_" + m_runTimestamp + ".csv";
int fh = FileOpen(fn, FILE_TXT|FILE_WRITE|FILE_COMMON); int fh = FileOpen(fn, FILE_TXT | FILE_WRITE | FILE_COMMON);
if(fh == INVALID_HANDLE) { Print("AgentInteractionCSV: errore apertura ", fn); return; } if(fh == INVALID_HANDLE) {
Print("AgentInteractionCSV: errore apertura ", fn);
return;
}
string header = "bar,time,combinedZ"; string header = "bar,time,combinedZ";
for(int i=0; i<agentCount; i++) { for(int i = 0; i < agentCount; i++) {
string n = agents[i].name; string n = agents[i].name;
header += "," + n + "_z," + n + "_weight," + n + "_rho," + n + "_bias," + n + "_biasStd," + n + "_rhoLearn," + n + "_rawSignal"; header += "," + n + "_z," + n + "_weight," + n + "_rho," + n + "_bias," + n + "_biasStd," + n + "_rhoLearn," + n + "_rawSignal";
} }
@@ -1629,10 +1679,10 @@ UpdateHealth(actualReturn);
int n = MathMin(histCount, MAX_HISTORY); int n = MathMin(histCount, MAX_HISTORY);
int start = (histCount >= MAX_HISTORY) ? histIdx : 0; int start = (histCount >= MAX_HISTORY) ? histIdx : 0;
for(int i=0; i<n; i++) { for(int i = 0; i < n; i++) {
int ii = (start + i) % MAX_HISTORY; int ii = (start + i) % MAX_HISTORY;
string line = (string)i + "," + TimeToString(history[ii].time) + "," + StringFormat("%+.6f", history[ii].combinedZ); string line = (string)i + "," + TimeToString(history[ii].time) + "," + StringFormat("%+.6f", history[ii].combinedZ);
for(int j=0; j<agentCount; j++) { for(int j = 0; j < agentCount; j++) {
line += "," + StringFormat("%+.4f", agentHistory[ii][j].lastZScore); line += "," + StringFormat("%+.4f", agentHistory[ii][j].lastZScore);
line += "," + StringFormat("%.4f", agentHistory[ii][j].weight); line += "," + StringFormat("%.4f", agentHistory[ii][j].weight);
line += "," + StringFormat("%+.4f", agentHistory[ii][j].rho); line += "," + StringFormat("%+.4f", agentHistory[ii][j].rho);
@@ -1650,11 +1700,14 @@ UpdateHealth(actualReturn);
// ===================== SAVE DECISION LOG CSV ===================== // ===================== SAVE DECISION LOG CSV =====================
void SaveDecisionLogCSV(string symbol, ENUM_TIMEFRAMES tf) const { void SaveDecisionLogCSV(string symbol, ENUM_TIMEFRAMES tf) const {
string fn = "DecisionLog_" + symbol + "_" + EnumToString(tf) + "_" + m_runTimestamp + ".csv"; string fn = "DecisionLog_" + symbol + "_" + EnumToString(tf) + "_" + m_runTimestamp + ".csv";
int fh = FileOpen(fn, FILE_TXT|FILE_WRITE|FILE_COMMON); int fh = FileOpen(fn, FILE_TXT | FILE_WRITE | FILE_COMMON);
if(fh == INVALID_HANDLE) { Print("DecisionLogCSV: errore apertura ", fn); return; } if(fh == INVALID_HANDLE) {
Print("DecisionLogCSV: errore apertura ", fn);
return;
}
FileWriteString(fh, "time,action,direction,zScore,combinedZ,price,ticket,agreeingCount,totalAgents,confidence,minZ\r\n"); FileWriteString(fh, "time,action,direction,zScore,combinedZ,price,ticket,agreeingCount,totalAgents,confidence,minZ\r\n");
for(int d=0; d<decisionCount; d++) { for(int d = 0; d < decisionCount; d++) {
string line = TimeToString(decisionLog[d].time); string line = TimeToString(decisionLog[d].time);
line += "," + decisionLog[d].action; line += "," + decisionLog[d].action;
line += "," + (string)decisionLog[d].direction; line += "," + (string)decisionLog[d].direction;
@@ -1671,5 +1724,5 @@ UpdateHealth(actualReturn);
FileClose(fh); FileClose(fh);
Print("Decision log salvato: ", fn, " (", decisionCount, " decisioni)"); Print("Decision log salvato: ", fn, " (", decisionCount, " decisioni)");
} }
}; };
#endif #endif