Add CSV exports: BarHistory, TradeHistory, AgentInteraction, DecisionLog, plus .gitignore
This commit is contained in:
@@ -18,9 +18,55 @@ struct BarSnapshot {
|
||||
double combinedZ;
|
||||
};
|
||||
|
||||
struct AgentSnapshot {
|
||||
double lastZScore;
|
||||
double weight;
|
||||
double rho;
|
||||
double bias;
|
||||
double biasStd;
|
||||
double rhoLearn;
|
||||
double rawSignal;
|
||||
};
|
||||
|
||||
struct TradeRecord {
|
||||
int ticket;
|
||||
bool isBuy;
|
||||
datetime entryTime;
|
||||
datetime closeTime;
|
||||
double entryPrice;
|
||||
double closePrice;
|
||||
double entryATR;
|
||||
double entryZ;
|
||||
double slPrice;
|
||||
double highestPrice;
|
||||
double lowestPrice;
|
||||
int barsHeld;
|
||||
double maeATR;
|
||||
double mfeATR;
|
||||
double actualReturn;
|
||||
double entryZScores[MAX_AGENTS];
|
||||
double entryFeatures[NN_FEATURES];
|
||||
string exitReason;
|
||||
};
|
||||
|
||||
struct DecisionRecord {
|
||||
datetime time;
|
||||
string action;
|
||||
int direction;
|
||||
double zScore;
|
||||
double combinedZ;
|
||||
double price;
|
||||
int ticket;
|
||||
int agreeingCount;
|
||||
int totalAgents;
|
||||
double confidence;
|
||||
double minZ;
|
||||
};
|
||||
|
||||
// Posizione aperta tracciata con MAE/MFE
|
||||
struct TrackedTrade {
|
||||
int ticket;
|
||||
datetime entryTime;
|
||||
double entryPrice;
|
||||
double entryATR;
|
||||
double entryZ;
|
||||
@@ -127,6 +173,14 @@ private:
|
||||
BarSnapshot history[MAX_HISTORY];
|
||||
int histIdx;
|
||||
int histCount;
|
||||
|
||||
// --- Export buffers ---
|
||||
AgentSnapshot agentHistory[MAX_HISTORY][MAX_AGENTS];
|
||||
TradeRecord completedTrades[];
|
||||
int completedTradeCount;
|
||||
DecisionRecord decisionLog[];
|
||||
int decisionCount;
|
||||
int decisionCapacity;
|
||||
|
||||
void InitCorrelation(int idx) {
|
||||
corrMeanX[idx] = 0;
|
||||
@@ -250,11 +304,20 @@ public:
|
||||
m_trainBuffer = new NNTrainBuffer();
|
||||
}
|
||||
|
||||
histIdx = 0;
|
||||
histCount = 0;
|
||||
}
|
||||
histIdx = 0;
|
||||
histCount = 0;
|
||||
|
||||
~Orchestrator() {
|
||||
completedTradeCount = 0;
|
||||
ArrayResize(completedTrades, 200);
|
||||
decisionCount = 0;
|
||||
decisionCapacity = 500;
|
||||
ArrayResize(decisionLog, decisionCapacity);
|
||||
for(int ai = 0; ai < MAX_HISTORY; ai++)
|
||||
for(int aj = 0; aj < MAX_AGENTS; aj++)
|
||||
agentHistory[ai][aj].lastZScore = 0;
|
||||
}
|
||||
|
||||
~Orchestrator() {
|
||||
ReleaseAgents();
|
||||
if(m_neuralNet) delete m_neuralNet;
|
||||
if(m_trainBuffer) delete m_trainBuffer;
|
||||
@@ -425,10 +488,11 @@ public:
|
||||
return -1;
|
||||
}
|
||||
openTrades[idx].ticket = ticket;
|
||||
openTrades[idx].entryPrice = price;
|
||||
openTrades[idx].entryATR = MathMax(atr, 1e-10);
|
||||
openTrades[idx].entryZ = z;
|
||||
openTrades[idx].isBuy = isBuy;
|
||||
openTrades[idx].entryPrice = price;
|
||||
openTrades[idx].entryATR = MathMax(atr, 1e-10);
|
||||
openTrades[idx].entryZ = z;
|
||||
openTrades[idx].isBuy = isBuy;
|
||||
openTrades[idx].entryTime = TimeCurrent();
|
||||
openTrades[idx].highestPrice = price;
|
||||
openTrades[idx].lowestPrice = price;
|
||||
openTrades[idx].barsHeld = 0;
|
||||
@@ -463,11 +527,40 @@ openTrades[idx].ticket = ticket;
|
||||
return idx;
|
||||
}
|
||||
|
||||
void OnTradeOpen(int ticket, double price, double atr) {
|
||||
AddTrade(ticket, price, atr, combinedZ, combinedZ > 0);
|
||||
}
|
||||
|
||||
void OnTradeClose(int ticket, double closePrice) {
|
||||
void OnTradeOpen(int ticket, double price, double atr) {
|
||||
AddTrade(ticket, price, atr, combinedZ, combinedZ > 0);
|
||||
LogDecision("ENTRY", combinedZ > 0 ? 1 : -1, 0, price, ticket);
|
||||
}
|
||||
|
||||
void LogDecision(string action, int dir, double minZ, double price, int ticket = 0) {
|
||||
if(decisionCount >= decisionCapacity) {
|
||||
decisionCapacity *= 2;
|
||||
ArrayResize(decisionLog, decisionCapacity);
|
||||
}
|
||||
DecisionRecord d;
|
||||
d.time = TimeCurrent();
|
||||
d.action = action;
|
||||
d.direction = dir;
|
||||
d.zScore = MathAbs(combinedZ);
|
||||
d.combinedZ = combinedZ;
|
||||
d.price = price;
|
||||
d.ticket = ticket;
|
||||
d.agreeingCount = 0;
|
||||
d.totalAgents = agentCount;
|
||||
d.confidence = MathAbs(combinedZ);
|
||||
d.minZ = minZ;
|
||||
if(action == "SIGNAL" || action == "ENTRY") {
|
||||
for(int i=0; i<agentCount; i++) {
|
||||
if(agents[i].enabled && MathAbs(agents[i].lastZScore) > 0.1) {
|
||||
if((agents[i].lastZScore > 0) == (dir > 0)) d.agreeingCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
decisionLog[decisionCount] = d;
|
||||
decisionCount++;
|
||||
}
|
||||
|
||||
void OnTradeClose(int ticket, double closePrice, string exitReason = "MANUAL") {
|
||||
// Trova il trade nell'array
|
||||
int idx = -1;
|
||||
for(int i=0; i<maxOpenTrades; i++) {
|
||||
@@ -572,10 +665,34 @@ UpdateCorrelation(i, openTrades[idx].entryZScores[i], actualReturnZ);
|
||||
}
|
||||
|
||||
UpdateHealth(actualReturn);
|
||||
LogHealth();
|
||||
LogHealth();
|
||||
|
||||
openTrades[idx].active = false;
|
||||
}
|
||||
// Save completed trade record
|
||||
int ct = completedTradeCount;
|
||||
ArrayResize(completedTrades, ct + 1);
|
||||
completedTrades[ct].ticket = openTrades[idx].ticket;
|
||||
completedTrades[ct].isBuy = openTrades[idx].isBuy;
|
||||
completedTrades[ct].entryPrice = openTrades[idx].entryPrice;
|
||||
completedTrades[ct].closePrice = closePrice;
|
||||
completedTrades[ct].entryATR = openTrades[idx].entryATR;
|
||||
completedTrades[ct].entryZ = openTrades[idx].entryZ;
|
||||
completedTrades[ct].slPrice = openTrades[idx].slPrice;
|
||||
completedTrades[ct].highestPrice = openTrades[idx].highestPrice;
|
||||
completedTrades[ct].lowestPrice = openTrades[idx].lowestPrice;
|
||||
completedTrades[ct].barsHeld = openTrades[idx].barsHeld;
|
||||
completedTrades[ct].maeATR = openTrades[idx].maeATR;
|
||||
completedTrades[ct].mfeATR = openTrades[idx].mfeATR;
|
||||
completedTrades[ct].actualReturn = actualReturn;
|
||||
completedTrades[ct].entryTime = 0;
|
||||
completedTrades[ct].closeTime = TimeCurrent();
|
||||
completedTrades[ct].exitReason = exitReason;
|
||||
for(int ei = 0; ei < agentCount; ei++) completedTrades[ct].entryZScores[ei] = openTrades[idx].entryZScores[ei];
|
||||
for(int ef = 0; ef < NN_FEATURES; ef++) completedTrades[ct].entryFeatures[ef] = openTrades[idx].entryFeatures[ef];
|
||||
|
||||
LogDecision("EXIT", openTrades[idx].isBuy ? 1 : -1, 0, closePrice, ticket);
|
||||
|
||||
openTrades[idx].active = false;
|
||||
}
|
||||
|
||||
// Trova un trade per ticket
|
||||
int FindTrade(int ticket) const {
|
||||
@@ -776,11 +893,20 @@ UpdateHealth(actualReturn);
|
||||
for(int i=0; i<MAX_AGENTS; i++) prevCorr[i] = 0;
|
||||
for(int i=0; i<ROLLING_TRADES; i++) rollingReturns[i] = 0;
|
||||
|
||||
histIdx = 0;
|
||||
histCount = 0;
|
||||
}
|
||||
|
||||
// --- Self-evaluation ---
|
||||
histIdx = 0;
|
||||
histCount = 0;
|
||||
|
||||
completedTradeCount = 0;
|
||||
ArrayResize(completedTrades, 200);
|
||||
decisionCount = 0;
|
||||
decisionCapacity = 500;
|
||||
ArrayResize(decisionLog, decisionCapacity);
|
||||
for(int ai = 0; ai < MAX_HISTORY; ai++)
|
||||
for(int aj = 0; aj < MAX_AGENTS; aj++)
|
||||
agentHistory[ai][aj].lastZScore = 0;
|
||||
}
|
||||
|
||||
// --- Self-evaluation ---
|
||||
void UpdateHealth(double actualReturn) {
|
||||
// Rolling returns buffer
|
||||
rollingReturns[rollingIdx] = actualReturn;
|
||||
@@ -856,8 +982,16 @@ UpdateHealth(actualReturn);
|
||||
void LogBarHistory(datetime time) {
|
||||
history[histIdx].time = time;
|
||||
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;
|
||||
agentHistory[histIdx][i].lastZScore = agents[i].lastZScore;
|
||||
agentHistory[histIdx][i].weight = agents[i].weight;
|
||||
agentHistory[histIdx][i].rho = GetCorrelation(i);
|
||||
agentHistory[histIdx][i].bias = agents[i].predictionError.Mean();
|
||||
agentHistory[histIdx][i].biasStd = agents[i].predictionError.Std();
|
||||
agentHistory[histIdx][i].rhoLearn = agents[i].predCorr.Ready() ? agents[i].predCorr.Correlation() : 0;
|
||||
agentHistory[histIdx][i].rawSignal = agents[i].lastRawSignal;
|
||||
}
|
||||
histIdx = (histIdx + 1) % MAX_HISTORY;
|
||||
if(histCount < MAX_HISTORY) histCount++;
|
||||
}
|
||||
@@ -1299,5 +1433,165 @@ UpdateHealth(actualReturn);
|
||||
FileClose(fh);
|
||||
Print("Analisi salvata: ", fn);
|
||||
}
|
||||
|
||||
// ===================== SAVE BAR HISTORY CSV =====================
|
||||
void SaveBarHistoryCSV(string symbol, ENUM_TIMEFRAMES tf) const {
|
||||
string fn = "BarHistory_" + symbol + "_" + EnumToString(tf) + ".csv";
|
||||
int fh = FileOpen(fn, FILE_TXT|FILE_WRITE|FILE_COMMON);
|
||||
if(fh == INVALID_HANDLE) { Print("BarHistoryCSV: errore apertura ", fn); return; }
|
||||
|
||||
string header = "bar,time,combinedZ";
|
||||
string agentNames[MAX_AGENTS];
|
||||
for(int i=0; i<agentCount; i++) {
|
||||
agentNames[i] = agents[i].name;
|
||||
header += "," + agentNames[i] + "_z";
|
||||
}
|
||||
header += ",regimeH,adxRaw,regimeConsensus,agreement,trendStrength,patternName";
|
||||
FileWriteString(fh, header + "\r\n");
|
||||
|
||||
int n = MathMin(histCount, MAX_HISTORY);
|
||||
int start = (histCount >= MAX_HISTORY) ? histIdx : 0;
|
||||
for(int i=0; i<n; i++) {
|
||||
int ii = (start + i) % MAX_HISTORY;
|
||||
string line = (string)i + "," + TimeToString(history[ii].time) + "," + StringFormat("%+.6f", history[ii].combinedZ);
|
||||
for(int j=0; j<agentCount; j++)
|
||||
line += "," + StringFormat("%+.6f", history[ii].z[j]);
|
||||
line += "," + StringFormat("%.4f", SHARED_regimeH);
|
||||
line += "," + StringFormat("%.1f", SHARED_adxRaw);
|
||||
line += "," + StringFormat("%+.4f", SHARED_regimeConsensus);
|
||||
line += "," + StringFormat("%.4f", SHARED_regimeAgreement);
|
||||
line += "," + StringFormat("%.4f", SHARED_trendStrength);
|
||||
line += "," + SHARED_patternName;
|
||||
FileWriteString(fh, line + "\r\n");
|
||||
}
|
||||
FileClose(fh);
|
||||
Print("Bar history salvata: ", fn, " (", n, " barre)");
|
||||
}
|
||||
|
||||
// ===================== SAVE TRADE HISTORY CSV =====================
|
||||
void SaveTradeHistoryCSV(string symbol, ENUM_TIMEFRAMES tf) const {
|
||||
string fn = "TradeHistory_" + symbol + "_" + EnumToString(tf) + ".csv";
|
||||
int fh = FileOpen(fn, FILE_TXT|FILE_WRITE|FILE_COMMON);
|
||||
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 agentNames[MAX_AGENTS];
|
||||
for(int i=0; i<agentCount; i++) {
|
||||
agentNames[i] = agents[i].name;
|
||||
header += "," + agentNames[i] + "_entryZ";
|
||||
}
|
||||
string featLabels[NN_FEATURES] = {"Hurst","ADX","MA","Momentum","Consensus","Hunter","Agreement","TrendStr"};
|
||||
for(int f=0; f<NN_FEATURES; f++) header += ",feat_" + featLabels[f];
|
||||
FileWriteString(fh, header + "\r\n");
|
||||
|
||||
// Completed trades
|
||||
for(int t=0; t<completedTradeCount; t++) {
|
||||
string line = (string)completedTrades[t].ticket;
|
||||
line += "," + (string)(completedTrades[t].isBuy ? 1 : 0);
|
||||
line += "," + TimeToString(completedTrades[t].entryTime);
|
||||
line += "," + TimeToString(completedTrades[t].closeTime);
|
||||
line += "," + (string)completedTrades[t].barsHeld;
|
||||
line += "," + StringFormat("%.5f", completedTrades[t].entryPrice);
|
||||
line += "," + StringFormat("%.5f", completedTrades[t].closePrice);
|
||||
line += "," + StringFormat("%.4f", completedTrades[t].entryATR);
|
||||
line += "," + StringFormat("%+.4f", completedTrades[t].entryZ);
|
||||
line += "," + StringFormat("%.5f", completedTrades[t].slPrice);
|
||||
line += "," + StringFormat("%.5f", completedTrades[t].highestPrice);
|
||||
line += "," + StringFormat("%.5f", completedTrades[t].lowestPrice);
|
||||
line += "," + StringFormat("%.4f", completedTrades[t].maeATR);
|
||||
line += "," + StringFormat("%.4f", completedTrades[t].mfeATR);
|
||||
line += "," + StringFormat("%+.4f", completedTrades[t].actualReturn);
|
||||
line += "," + completedTrades[t].exitReason;
|
||||
for(int j=0; j<agentCount; j++)
|
||||
line += "," + StringFormat("%+.4f", completedTrades[t].entryZScores[j]);
|
||||
for(int f=0; f<NN_FEATURES; f++)
|
||||
line += "," + StringFormat("%+.4f", completedTrades[t].entryFeatures[f]);
|
||||
FileWriteString(fh, line + "\r\n");
|
||||
}
|
||||
|
||||
// Open trades (still active)
|
||||
for(int i=0; i<maxOpenTrades; i++) {
|
||||
if(!openTrades[i].active) continue;
|
||||
string line = (string)openTrades[i].ticket;
|
||||
line += "," + (string)(openTrades[i].isBuy ? 1 : 0);
|
||||
line += ",,"; // no close time yet
|
||||
line += "," + (string)openTrades[i].barsHeld;
|
||||
line += "," + StringFormat("%.5f", openTrades[i].entryPrice);
|
||||
line += ","; // no close price yet
|
||||
line += "," + StringFormat("%.4f", openTrades[i].entryATR);
|
||||
line += "," + StringFormat("%+.4f", openTrades[i].entryZ);
|
||||
line += "," + StringFormat("%.5f", openTrades[i].slPrice);
|
||||
line += "," + StringFormat("%.5f", openTrades[i].highestPrice);
|
||||
line += "," + StringFormat("%.5f", openTrades[i].lowestPrice);
|
||||
line += "," + StringFormat("%.4f", openTrades[i].maeATR);
|
||||
line += "," + StringFormat("%.4f", openTrades[i].mfeATR);
|
||||
line += ",,OPEN"; // no return, exit=OPEN
|
||||
for(int j=0; j<agentCount; j++)
|
||||
line += "," + StringFormat("%+.4f", openTrades[i].entryZScores[j]);
|
||||
for(int f=0; f<NN_FEATURES; f++)
|
||||
line += "," + StringFormat("%+.4f", openTrades[i].entryFeatures[f]);
|
||||
FileWriteString(fh, line + "\r\n");
|
||||
}
|
||||
FileClose(fh);
|
||||
Print("Trade history salvata: ", fn, " (", completedTradeCount, " completati, ", OpenTradeCount(), " aperti)");
|
||||
}
|
||||
|
||||
// ===================== SAVE AGENT INTERACTION CSV =====================
|
||||
void SaveAgentInteractionCSV(string symbol, ENUM_TIMEFRAMES tf) const {
|
||||
string fn = "AgentInteraction_" + symbol + "_" + EnumToString(tf) + ".csv";
|
||||
int fh = FileOpen(fn, FILE_TXT|FILE_WRITE|FILE_COMMON);
|
||||
if(fh == INVALID_HANDLE) { Print("AgentInteractionCSV: errore apertura ", fn); return; }
|
||||
|
||||
string header = "bar,time,combinedZ";
|
||||
for(int i=0; i<agentCount; i++) {
|
||||
string n = agents[i].name;
|
||||
header += "," + n + "_z," + n + "_weight," + n + "_rho," + n + "_bias," + n + "_biasStd," + n + "_rhoLearn," + n + "_rawSignal";
|
||||
}
|
||||
FileWriteString(fh, header + "\r\n");
|
||||
|
||||
int n = MathMin(histCount, MAX_HISTORY);
|
||||
int start = (histCount >= MAX_HISTORY) ? histIdx : 0;
|
||||
for(int i=0; i<n; i++) {
|
||||
int ii = (start + i) % MAX_HISTORY;
|
||||
string line = (string)i + "," + TimeToString(history[ii].time) + "," + StringFormat("%+.6f", history[ii].combinedZ);
|
||||
for(int j=0; j<agentCount; j++) {
|
||||
line += "," + StringFormat("%+.4f", agentHistory[ii][j].lastZScore);
|
||||
line += "," + StringFormat("%.4f", agentHistory[ii][j].weight);
|
||||
line += "," + StringFormat("%+.4f", agentHistory[ii][j].rho);
|
||||
line += "," + StringFormat("%+.4f", agentHistory[ii][j].bias);
|
||||
line += "," + StringFormat("%.4f", agentHistory[ii][j].biasStd);
|
||||
line += "," + StringFormat("%+.4f", agentHistory[ii][j].rhoLearn);
|
||||
line += "," + StringFormat("%+.4f", agentHistory[ii][j].rawSignal);
|
||||
}
|
||||
FileWriteString(fh, line + "\r\n");
|
||||
}
|
||||
FileClose(fh);
|
||||
Print("Agent interaction salvata: ", fn, " (", n, " barre)");
|
||||
}
|
||||
|
||||
// ===================== SAVE DECISION LOG CSV =====================
|
||||
void SaveDecisionLogCSV(string symbol, ENUM_TIMEFRAMES tf) const {
|
||||
string fn = "DecisionLog_" + symbol + "_" + EnumToString(tf) + ".csv";
|
||||
int fh = FileOpen(fn, FILE_TXT|FILE_WRITE|FILE_COMMON);
|
||||
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");
|
||||
for(int d=0; d<decisionCount; d++) {
|
||||
string line = TimeToString(decisionLog[d].time);
|
||||
line += "," + decisionLog[d].action;
|
||||
line += "," + (string)decisionLog[d].direction;
|
||||
line += "," + StringFormat("%+.4f", decisionLog[d].zScore);
|
||||
line += "," + StringFormat("%+.4f", decisionLog[d].combinedZ);
|
||||
line += "," + StringFormat("%.5f", decisionLog[d].price);
|
||||
line += "," + (string)decisionLog[d].ticket;
|
||||
line += "," + (string)decisionLog[d].agreeingCount;
|
||||
line += "," + (string)decisionLog[d].totalAgents;
|
||||
line += "," + StringFormat("%.4f", decisionLog[d].confidence);
|
||||
line += "," + StringFormat("%.4f", decisionLog[d].minZ);
|
||||
FileWriteString(fh, line + "\r\n");
|
||||
}
|
||||
FileClose(fh);
|
||||
Print("Decision log salvato: ", fn, " (", decisionCount, " decisioni)");
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user