mql5/Experts/Advisors/DualEA/Include/CInsightsRealtime.mqh

261 lines
8.1 KiB
MQL5
Raw Permalink Normal View History

2026-02-24 12:47:37 -05:00
//+------------------------------------------------------------------+
//| CInsightsRealtime.mqh - Real-time Insights Engine |
//| Provides real-time performance insights for trading signals |
//+------------------------------------------------------------------+
#ifndef CINSIGHTSREALTIME_MQH
#define CINSIGHTSREALTIME_MQH
#include <Object.mqh>
//+------------------------------------------------------------------+
//| Insight Data Structure |
//+------------------------------------------------------------------+
struct SInsightData
{
string strategy;
string symbol;
double win_rate;
double profit_factor;
double expectancy;
int total_trades;
int winning_trades;
int losing_trades;
double avg_profit;
double avg_loss;
double max_drawdown;
double sharpe_ratio;
datetime last_update;
bool valid;
};
//+------------------------------------------------------------------+
//| Insights Realtime Class |
//+------------------------------------------------------------------+
class CInsightsRealtime : public CObject
{
private:
SInsightData m_insights[];
int m_insight_count;
int m_max_insights;
int m_min_trades_for_validity;
double m_decay_factor;
int FindInsightIndex(const string strategy, const string symbol)
{
for(int i = 0; i < m_insight_count; i++)
{
if(m_insights[i].strategy == strategy && m_insights[i].symbol == symbol)
return i;
}
return -1;
}
public:
CInsightsRealtime()
{
m_insight_count = 0;
m_max_insights = 1000;
m_min_trades_for_validity = 10;
m_decay_factor = 0.95;
ArrayResize(m_insights, 0);
}
~CInsightsRealtime()
{
ArrayResize(m_insights, 0);
}
bool Initialize()
{
Print("[InsightsRealtime] Initialized");
return true;
}
void Shutdown()
{
ArrayResize(m_insights, 0);
m_insight_count = 0;
}
// Update insight based on completed trade
void OnTradeCompleted(const string strategy, const string symbol,
double pnl, double r_multiple)
{
int idx = FindInsightIndex(strategy, symbol);
if(idx < 0)
{
// Create new insight entry
idx = m_insight_count;
if(idx >= m_max_insights)
{
Print("[InsightsRealtime] Warning: Max insights reached");
return;
}
ArrayResize(m_insights, idx + 1);
m_insights[idx].strategy = strategy;
m_insights[idx].symbol = symbol;
m_insights[idx].win_rate = 0.0;
m_insights[idx].profit_factor = 0.0;
m_insights[idx].expectancy = 0.0;
m_insights[idx].total_trades = 0;
m_insights[idx].winning_trades = 0;
m_insights[idx].losing_trades = 0;
m_insights[idx].avg_profit = 0.0;
m_insights[idx].avg_loss = 0.0;
m_insights[idx].max_drawdown = 0.0;
m_insights[idx].sharpe_ratio = 0.0;
m_insights[idx].valid = false;
m_insight_count++;
}
// Update statistics directly on array element
m_insights[idx].total_trades++;
if(pnl > 0)
{
m_insights[idx].winning_trades++;
m_insights[idx].avg_profit = (m_insights[idx].avg_profit * (m_insights[idx].winning_trades - 1) + pnl) / m_insights[idx].winning_trades;
}
else
{
m_insights[idx].losing_trades++;
m_insights[idx].avg_loss = (m_insights[idx].avg_loss * (m_insights[idx].losing_trades - 1) + MathAbs(pnl)) / m_insights[idx].losing_trades;
}
m_insights[idx].win_rate = (double)m_insights[idx].winning_trades / m_insights[idx].total_trades;
double gross_profit = m_insights[idx].avg_profit * m_insights[idx].winning_trades;
double gross_loss = m_insights[idx].avg_loss * m_insights[idx].losing_trades;
m_insights[idx].profit_factor = (gross_loss > 0) ? gross_profit / gross_loss : 0.0;
double win_prob = m_insights[idx].win_rate;
double loss_prob = 1.0 - win_prob;
m_insights[idx].expectancy = (win_prob * m_insights[idx].avg_profit) - (loss_prob * m_insights[idx].avg_loss);
if(r_multiple < 0)
{
double current_dd = MathAbs(r_multiple);
if(current_dd > m_insights[idx].max_drawdown)
m_insights[idx].max_drawdown = current_dd;
}
m_insights[idx].valid = (m_insights[idx].total_trades >= m_min_trades_for_validity);
m_insights[idx].last_update = TimeCurrent();
}
// Get signal confidence based on historical performance
double GetSignalConfidence(const string strategy, const string symbol)
{
int idx = FindInsightIndex(strategy, symbol);
if(idx < 0) return 0.5; // Default neutral confidence
if(!m_insights[idx].valid || m_insights[idx].total_trades < m_min_trades_for_validity)
return 0.5;
// Calculate confidence based on win rate and profit factor
double win_confidence = m_insights[idx].win_rate;
double pf_confidence = MathMin(m_insights[idx].profit_factor / 2.0, 1.0); // Cap at 1.0, normalize
// Combine factors
double confidence = (win_confidence * 0.6) + (pf_confidence * 0.4);
// Apply decay for stale data
datetime now = TimeCurrent();
int hours_since_update = (int)((now - m_insights[idx].last_update) / 3600);
if(hours_since_update > 24)
{
double age_factor = MathPow(m_decay_factor, hours_since_update / 24.0);
confidence *= age_factor;
}
return MathMin(MathMax(confidence, 0.0), 1.0);
}
// Get full insight data
bool GetInsight(const string strategy, const string symbol, SInsightData &data)
{
int idx = FindInsightIndex(strategy, symbol);
if(idx < 0) return false;
data = m_insights[idx];
return true;
}
// Check if strategy/symbol combination has valid insights
bool HasValidInsight(const string strategy, const string symbol)
{
int idx = FindInsightIndex(strategy, symbol);
if(idx < 0) return false;
return m_insights[idx].valid;
}
// Get metrics for strategy selection
bool GetStrategyMetrics(const string strategy, const string symbol,
double &win_rate, double &profit_factor, double &expectancy)
{
int idx = FindInsightIndex(strategy, symbol);
if(idx < 0 || !m_insights[idx].valid)
{
win_rate = 0.5;
profit_factor = 1.0;
expectancy = 0.0;
return false;
}
win_rate = m_insights[idx].win_rate;
profit_factor = m_insights[idx].profit_factor;
expectancy = m_insights[idx].expectancy;
return true;
}
// Get best performing strategy for symbol
string GetBestStrategy(const string symbol)
{
string best_strategy = "";
double best_score = -1.0;
for(int i = 0; i < m_insight_count; i++)
{
if(m_insights[i].symbol == symbol && m_insights[i].valid)
{
// Score based on expectancy and win rate
double score = m_insights[i].expectancy * m_insights[i].win_rate;
if(score > best_score)
{
best_score = score;
best_strategy = m_insights[i].strategy;
}
}
}
return best_strategy;
}
// Reset all insights
void Reset()
{
ArrayResize(m_insights, 0);
m_insight_count = 0;
}
// Get total insight count
int GetCount() const { return m_insight_count; }
// Get valid insight count
int GetValidCount()
{
int count = 0;
for(int i = 0; i < m_insight_count; i++)
{
if(m_insights[i].valid)
count++;
}
return count;
}
void SetMinTradesForValidity(int min_trades) { m_min_trades_for_validity = min_trades; }
int GetMinTradesForValidity() const { return m_min_trades_for_validity; }
};
#endif // CINSIGHTSREALTIME_MQH