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:
co-authored by
Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
parent
a8b4a7d3ff
commit
bb670836e1
@@ -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
|
||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user