956 lines
40 KiB
MQL5
956 lines
40 KiB
MQL5
|
//+------------------------------------------------------------------+
|
||
|
//| MultiTradeReporter_v71.mqh |
|
||
|
//| Institutional Grade Multi-Source Reporting |
|
||
|
//| Performance Attribution, Risk Analytics, Compliance |
|
||
|
//+------------------------------------------------------------------+
|
||
|
#ifndef MULTI_TRADE_REPORTER_V71_MQH
|
||
|
#define MULTI_TRADE_REPORTER_V71_MQH
|
||
|
|
||
|
#include "DataTypes_v71.mqh"
|
||
|
#include <Files/FileTxt.mqh>
|
||
|
#include <Files/FileBin.mqh>
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Report Types |
|
||
|
//+------------------------------------------------------------------+
|
||
|
enum ENUM_REPORT_TYPE
|
||
|
{
|
||
|
REPORT_DAILY = 0,
|
||
|
REPORT_WEEKLY = 1,
|
||
|
REPORT_MONTHLY = 2,
|
||
|
REPORT_QUARTERLY = 3,
|
||
|
REPORT_ANNUAL = 4,
|
||
|
REPORT_CUSTOM = 5
|
||
|
};
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Performance Attribution |
|
||
|
//+------------------------------------------------------------------+
|
||
|
struct PerformanceAttribution
|
||
|
{
|
||
|
double strategy_contribution;
|
||
|
double timing_contribution;
|
||
|
double selection_contribution;
|
||
|
double allocation_effect;
|
||
|
double interaction_effect;
|
||
|
double currency_effect;
|
||
|
double total_attribution;
|
||
|
};
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Risk Attribution |
|
||
|
//+------------------------------------------------------------------+
|
||
|
struct RiskAttribution
|
||
|
{
|
||
|
double systematic_risk;
|
||
|
double specific_risk;
|
||
|
double concentration_risk;
|
||
|
double correlation_risk;
|
||
|
double liquidity_risk;
|
||
|
double operational_risk;
|
||
|
double model_risk;
|
||
|
};
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Compliance Metrics |
|
||
|
//+------------------------------------------------------------------+
|
||
|
struct ComplianceMetrics
|
||
|
{
|
||
|
int violations_count;
|
||
|
double max_position_breach;
|
||
|
double max_drawdown_breach;
|
||
|
double max_var_breach;
|
||
|
int unauthorized_trades;
|
||
|
datetime last_violation_time;
|
||
|
string violation_details[];
|
||
|
};
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Multi-Trade Reporter Class - Institutional |
|
||
|
//+------------------------------------------------------------------+
|
||
|
class CMultiTradeReporterV71
|
||
|
{
|
||
|
private:
|
||
|
//--- Configuration
|
||
|
string m_report_path;
|
||
|
ENUM_REPORT_TYPE m_report_type;
|
||
|
bool m_csv_export;
|
||
|
bool m_html_export;
|
||
|
bool m_json_export;
|
||
|
bool m_fix_export;
|
||
|
int m_report_frequency;
|
||
|
|
||
|
//--- Tracking
|
||
|
datetime m_last_report_time;
|
||
|
int m_report_count;
|
||
|
|
||
|
//--- Performance attribution
|
||
|
PerformanceAttribution m_attribution;
|
||
|
RiskAttribution m_risk_attribution;
|
||
|
ComplianceMetrics m_compliance;
|
||
|
|
||
|
//--- Report templates
|
||
|
string m_daily_template;
|
||
|
string m_institutional_template;
|
||
|
string m_regulatory_template;
|
||
|
|
||
|
//--- Helper methods
|
||
|
void GenerateHTMLReport(ManagedTradeV71 &trades[], PerformanceMetricsV71 &performance);
|
||
|
void GenerateJSONReport(ManagedTradeV71 &trades[], PerformanceMetricsV71 &performance);
|
||
|
void GenerateFIXReport(ManagedTradeV71 &trades[], PerformanceMetricsV71 &performance);
|
||
|
void GenerateComplianceReport(ComplianceMetrics &compliance);
|
||
|
|
||
|
//--- Analysis methods
|
||
|
void CalculatePerformanceAttribution(ManagedTradeV71 &trades[]);
|
||
|
void CalculateRiskAttribution(ManagedTradeV71 &trades[]);
|
||
|
void AnalyzeTradesByStrategy(ManagedTradeV71 &trades[], string &output);
|
||
|
void AnalyzeTradesByTimeframe(ManagedTradeV71 &trades[], string &output);
|
||
|
void AnalyzeExecutionQuality(ManagedTradeV71 &trades[], string &output);
|
||
|
|
||
|
//--- Statistical analysis
|
||
|
double CalculateInformationRatio(double returns[], double benchmark[]);
|
||
|
double CalculateMaximumLikelihoodEstimate(double data[]);
|
||
|
void CalculateRegressionAnalysis(double x[], double y[], double &alpha, double &beta);
|
||
|
|
||
|
public:
|
||
|
CMultiTradeReporterV71();
|
||
|
~CMultiTradeReporterV71();
|
||
|
|
||
|
//--- Initialization
|
||
|
bool Initialize(string report_path, ENUM_REPORT_TYPE type = REPORT_DAILY);
|
||
|
void SetExportFormats(bool csv, bool html, bool json, bool fix);
|
||
|
void SetReportFrequency(int minutes) { m_report_frequency = minutes; }
|
||
|
|
||
|
//--- Main reporting
|
||
|
void GenerateInstitutionalReport(PerformanceMetricsV71 &performance,
|
||
|
ManagedTradeV71 &trades[],
|
||
|
ExecutionMetrics &execution);
|
||
|
void GenerateRegulatoryReport(ManagedTradeV71 &trades[],
|
||
|
ComplianceMetrics &compliance);
|
||
|
void GenerateRiskReport(ManagedTradeV71 &trades[],
|
||
|
SystemStateV71 &state);
|
||
|
|
||
|
//--- Performance attribution
|
||
|
void UpdatePerformanceAttribution(ManagedTradeV71 &trades[],
|
||
|
PerformanceMetricsV71 &performance);
|
||
|
PerformanceAttribution GetAttribution() { return m_attribution; }
|
||
|
|
||
|
//--- Specialized reports
|
||
|
void GenerateVaRReport(ManagedTradeV71 &trades[], double var, double cvar);
|
||
|
void GenerateStressTestReport(ManagedTradeV71 &trades[], double scenarios[]);
|
||
|
void GenerateCorrelationReport(CorrelationMatrix &correlations);
|
||
|
void GenerateLiquidityReport(ManagedTradeV71 &trades[]);
|
||
|
|
||
|
//--- Trade analysis
|
||
|
void GenerateTradeAnalysis(ManagedTradeV71 &trades[]);
|
||
|
void GenerateMLPerformanceReport(ManagedTradeV71 &trades[]);
|
||
|
void GenerateOrderFlowReport(OrderFlowData &flow_data[]);
|
||
|
|
||
|
//--- Compliance and audit
|
||
|
void CheckCompliance(ManagedTradeV71 &trades[], ComplianceMetrics &metrics);
|
||
|
void GenerateAuditTrail(ManagedTradeV71 &trades[]);
|
||
|
void LogComplianceViolation(string violation_type, string details);
|
||
|
|
||
|
//--- Export methods
|
||
|
void ExportToBloomberg(ManagedTradeV71 &trades[]);
|
||
|
void ExportToFIX(ManagedTradeV71 &trades[]);
|
||
|
void ExportToREDI(ManagedTradeV71 &trades[]);
|
||
|
|
||
|
//--- Real-time updates
|
||
|
void SendRealtimeUpdate(string metric, double value);
|
||
|
void BroadcastPerformance(PerformanceMetricsV71 &performance);
|
||
|
|
||
|
//--- Getters
|
||
|
datetime GetLastReportTime() { return m_last_report_time; }
|
||
|
int GetReportCount() { return m_report_count; }
|
||
|
};
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Constructor |
|
||
|
//+------------------------------------------------------------------+
|
||
|
CMultiTradeReporterV71::CMultiTradeReporterV71()
|
||
|
{
|
||
|
m_report_path = "InstitutionalReports\\";
|
||
|
m_report_type = REPORT_DAILY;
|
||
|
m_csv_export = true;
|
||
|
m_html_export = true;
|
||
|
m_json_export = true;
|
||
|
m_fix_export = false;
|
||
|
m_report_frequency = 3600; // Hourly
|
||
|
m_last_report_time = 0;
|
||
|
m_report_count = 0;
|
||
|
|
||
|
//--- Initialize attribution
|
||
|
ZeroMemory(m_attribution);
|
||
|
ZeroMemory(m_risk_attribution);
|
||
|
ZeroMemory(m_compliance);
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Destructor |
|
||
|
//+------------------------------------------------------------------+
|
||
|
CMultiTradeReporterV71::~CMultiTradeReporterV71()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Initialize reporter |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool CMultiTradeReporterV71::Initialize(string report_path, ENUM_REPORT_TYPE type)
|
||
|
{
|
||
|
m_report_path = report_path;
|
||
|
m_report_type = type;
|
||
|
|
||
|
//--- Create directory structure
|
||
|
if(!FileIsExist(m_report_path))
|
||
|
{
|
||
|
Print("Please create directory: ", m_report_path);
|
||
|
}
|
||
|
|
||
|
//--- Load report templates
|
||
|
m_daily_template = "Daily Institutional Report";
|
||
|
m_institutional_template = "Institutional Trading Report";
|
||
|
m_regulatory_template = "Regulatory Compliance Report";
|
||
|
|
||
|
Print("MultiTradeReporterV71 initialized: Path=", m_report_path,
|
||
|
", Type=", EnumToString(m_report_type));
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Generate institutional report |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void CMultiTradeReporterV71::GenerateInstitutionalReport(PerformanceMetricsV71 &performance,
|
||
|
ManagedTradeV71 &trades[],
|
||
|
ExecutionMetrics &execution)
|
||
|
{
|
||
|
//--- Check report frequency
|
||
|
if(TimeCurrent() - m_last_report_time < m_report_frequency && m_report_frequency > 0)
|
||
|
return;
|
||
|
|
||
|
m_report_count++;
|
||
|
string timestamp = TimeToString(TimeCurrent(), TIME_DATE|TIME_MINUTES);
|
||
|
StringReplace(timestamp, ":", "_");
|
||
|
StringReplace(timestamp, " ", "_");
|
||
|
|
||
|
//--- Main report content
|
||
|
string report = "";
|
||
|
report += "╔══════════════════════════════════════════════════════════════╗\n";
|
||
|
report += "║ INSTITUTIONAL TRADING REPORT - ERMT 7.1 ║\n";
|
||
|
report += "╚══════════════════════════════════════════════════════════════╝\n\n";
|
||
|
|
||
|
report += "Report Date: " + TimeToString(TimeCurrent()) + "\n";
|
||
|
report += "Report Number: " + IntegerToString(m_report_count) + "\n";
|
||
|
report += "Reporting Period: " + EnumToString(m_report_type) + "\n\n";
|
||
|
|
||
|
//--- Executive Summary
|
||
|
report += "┌─────────────────────────────────────────────────────────────┐\n";
|
||
|
report += "│ EXECUTIVE SUMMARY │\n";
|
||
|
report += "└─────────────────────────────────────────────────────────────┘\n";
|
||
|
|
||
|
double starting_balance = AccountInfoDouble(ACCOUNT_BALANCE) - performance.net_profit;
|
||
|
double roi = (starting_balance > 0) ? (performance.net_profit / starting_balance * 100) : 0;
|
||
|
|
||
|
report += "Starting Capital: $" + DoubleToString(starting_balance, 2) + "\n";
|
||
|
report += "Current Capital: $" + DoubleToString(AccountInfoDouble(ACCOUNT_BALANCE), 2) + "\n";
|
||
|
report += "Net P&L: $" + DoubleToString(performance.net_profit, 2) + "\n";
|
||
|
report += "Return on Investment: " + DoubleToString(roi, 2) + "%\n";
|
||
|
report += "Sharpe Ratio: " + DoubleToString(performance.sharpe_ratio, 3) + "\n";
|
||
|
report += "Information Ratio: " + DoubleToString(performance.information_ratio, 3) + "\n\n";
|
||
|
|
||
|
//--- Risk Analytics
|
||
|
report += "┌─────────────────────────────────────────────────────────────┐\n";
|
||
|
report += "│ RISK ANALYTICS │\n";
|
||
|
report += "└─────────────────────────────────────────────────────────────┘\n";
|
||
|
|
||
|
report += "Value at Risk (95%): " + DoubleToString(performance.var_95, 2) + "%\n";
|
||
|
report += "Conditional VaR (95%): " + DoubleToString(performance.cvar_95, 2) + "%\n";
|
||
|
report += "Maximum Drawdown: " + DoubleToString(performance.max_drawdown_percent, 2) + "%\n";
|
||
|
report += "Beta: " + DoubleToString(performance.beta, 3) + "\n";
|
||
|
report += "Tracking Error: " + DoubleToString(performance.tracking_error, 3) + "%\n\n";
|
||
|
|
||
|
//--- Performance Attribution
|
||
|
if(m_attribution.total_attribution != 0)
|
||
|
{
|
||
|
report += "┌─────────────────────────────────────────────────────────────┐\n";
|
||
|
report += "│ PERFORMANCE ATTRIBUTION │\n";
|
||
|
report += "└─────────────────────────────────────────────────────────────┘\n";
|
||
|
|
||
|
report += "Strategy Selection: " + DoubleToString(m_attribution.selection_contribution * 100, 2) + "%\n";
|
||
|
report += "Market Timing: " + DoubleToString(m_attribution.timing_contribution * 100, 2) + "%\n";
|
||
|
report += "Asset Allocation: " + DoubleToString(m_attribution.allocation_effect * 100, 2) + "%\n";
|
||
|
report += "Currency Effect: " + DoubleToString(m_attribution.currency_effect * 100, 2) + "%\n";
|
||
|
report += "Total Attribution: " + DoubleToString(m_attribution.total_attribution * 100, 2) + "%\n\n";
|
||
|
}
|
||
|
|
||
|
//--- Execution Quality
|
||
|
report += "┌─────────────────────────────────────────────────────────────┐\n";
|
||
|
report += "│ EXECUTION QUALITY │\n";
|
||
|
report += "└─────────────────────────────────────────────────────────────┘\n";
|
||
|
|
||
|
report += "Total Executions: " + IntegerToString(execution.fills_count) + "\n";
|
||
|
report += "Average Slippage: " + DoubleToString(execution.avg_slippage, 2) + " pips\n";
|
||
|
report += "Positive Slippage Rate: " + DoubleToString(execution.positive_slippage_rate * 100, 1) + "%\n";
|
||
|
report += "Average Fill Time: " + DoubleToString(execution.avg_fill_time_ms, 0) + " ms\n";
|
||
|
report += "VWAP Tracking Error: " + DoubleToString(execution.vwap_tracking_error, 3) + "\n";
|
||
|
report += "Price Improvement: $" + DoubleToString(execution.improvement_amount, 2) + "\n\n";
|
||
|
|
||
|
//--- Position Analysis
|
||
|
report += "┌─────────────────────────────────────────────────────────────┐\n";
|
||
|
report += "│ POSITION ANALYSIS │\n";
|
||
|
report += "└─────────────────────────────────────────────────────────────┘\n";
|
||
|
|
||
|
int trade_count = ArraySize(trades);
|
||
|
report += "Active Positions: " + IntegerToString(trade_count) + "\n";
|
||
|
|
||
|
if(trade_count > 0)
|
||
|
{
|
||
|
//--- Group by symbol
|
||
|
string symbols[];
|
||
|
double exposures[];
|
||
|
int symbol_count = 0;
|
||
|
|
||
|
for(int i = 0; i < trade_count; i++)
|
||
|
{
|
||
|
int idx = -1;
|
||
|
for(int j = 0; j < symbol_count; j++)
|
||
|
{
|
||
|
if(symbols[j] == trades[i].symbol)
|
||
|
{
|
||
|
idx = j;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(idx < 0)
|
||
|
{
|
||
|
ArrayResize(symbols, symbol_count + 1);
|
||
|
ArrayResize(exposures, symbol_count + 1);
|
||
|
symbols[symbol_count] = trades[i].symbol;
|
||
|
exposures[symbol_count] = trades[i].risk_percent;
|
||
|
symbol_count++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
exposures[idx] += trades[i].risk_percent;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
report += "\nExposure by Symbol:\n";
|
||
|
for(int i = 0; i < symbol_count; i++)
|
||
|
{
|
||
|
report += " " + symbols[i] + ": " + DoubleToString(exposures[i], 2) + "%\n";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//--- Trade Analysis
|
||
|
string trade_analysis;
|
||
|
AnalyzeTradesByStrategy(trades, trade_analysis);
|
||
|
report += "\n" + trade_analysis;
|
||
|
|
||
|
//--- Compliance Check
|
||
|
if(m_compliance.violations_count > 0)
|
||
|
{
|
||
|
report += "\n┌─────────────────────────────────────────────────────────────┐\n";
|
||
|
report += "│ COMPLIANCE ALERTS │\n";
|
||
|
report += "└─────────────────────────────────────────────────────────────┘\n";
|
||
|
report += "Total Violations: " + IntegerToString(m_compliance.violations_count) + "\n";
|
||
|
|
||
|
for(int i = 0; i < ArraySize(m_compliance.violation_details); i++)
|
||
|
{
|
||
|
report += " - " + m_compliance.violation_details[i] + "\n";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//--- Save report
|
||
|
string filename = m_report_path + "Institutional_" + timestamp;
|
||
|
|
||
|
//--- Text format
|
||
|
int handle = FileOpen(filename + ".txt", FILE_WRITE|FILE_TXT|FILE_ANSI);
|
||
|
if(handle != INVALID_HANDLE)
|
||
|
{
|
||
|
FileWrite(handle, report);
|
||
|
FileClose(handle);
|
||
|
}
|
||
|
|
||
|
//--- Additional formats
|
||
|
if(m_csv_export)
|
||
|
GenerateCSVReport(trades, performance);
|
||
|
|
||
|
if(m_html_export)
|
||
|
GenerateHTMLReport(trades, performance);
|
||
|
|
||
|
if(m_json_export)
|
||
|
GenerateJSONReport(trades, performance);
|
||
|
|
||
|
if(m_fix_export)
|
||
|
GenerateFIXReport(trades, performance);
|
||
|
|
||
|
m_last_report_time = TimeCurrent();
|
||
|
Print("Institutional report generated: ", filename);
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Generate CSV report |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void CMultiTradeReporterV71::GenerateCSVReport(ManagedTradeV71 &trades[],
|
||
|
PerformanceMetricsV71 &performance)
|
||
|
{
|
||
|
string timestamp = TimeToString(TimeCurrent(), TIME_DATE|TIME_MINUTES);
|
||
|
StringReplace(timestamp, ":", "_");
|
||
|
StringReplace(timestamp, " ", "_");
|
||
|
|
||
|
string filename = m_report_path + "Trades_" + timestamp + ".csv";
|
||
|
int handle = FileOpen(filename, FILE_WRITE|FILE_CSV|FILE_ANSI, ',');
|
||
|
|
||
|
if(handle == INVALID_HANDLE) return;
|
||
|
|
||
|
//--- Header with extended fields
|
||
|
FileWrite(handle, "Ticket", "Symbol", "Type", "Volume", "Entry", "Current",
|
||
|
"SL", "TP", "Profit", "Commission", "Swap", "Risk%", "RMultiple",
|
||
|
"MAE", "MFE", "ExpectedReturn", "PredictedVol", "MLConfidence",
|
||
|
"VaRContribution", "CorrelationRisk", "LiquidityScore",
|
||
|
"ExecutionQuality", "EntryAlgo", "Magic", "OpenTime", "BarsHeld", "Comment");
|
||
|
|
||
|
//--- Trade data
|
||
|
int trade_count = ArraySize(trades);
|
||
|
for(int i = 0; i < trade_count; i++)
|
||
|
{
|
||
|
double current_price = (trades[i].type == POSITION_TYPE_BUY) ?
|
||
|
SymbolInfoDouble(trades[i].symbol, SYMBOL_BID) :
|
||
|
SymbolInfoDouble(trades[i].symbol, SYMBOL_ASK);
|
||
|
|
||
|
FileWrite(handle,
|
||
|
trades[i].ticket,
|
||
|
trades[i].symbol,
|
||
|
(trades[i].type == POSITION_TYPE_BUY) ? "BUY" : "SELL",
|
||
|
trades[i].volume,
|
||
|
trades[i].open_price,
|
||
|
current_price,
|
||
|
trades[i].sl,
|
||
|
trades[i].tp,
|
||
|
trades[i].profit,
|
||
|
trades[i].commission,
|
||
|
trades[i].swap,
|
||
|
trades[i].risk_percent,
|
||
|
trades[i].r_multiple,
|
||
|
trades[i].mae,
|
||
|
trades[i].mfe,
|
||
|
trades[i].expected_return,
|
||
|
trades[i].predicted_volatility,
|
||
|
trades[i].ml_confidence,
|
||
|
trades[i].var_contribution,
|
||
|
trades[i].correlation_risk,
|
||
|
trades[i].liquidity_score,
|
||
|
trades[i].execution_quality,
|
||
|
trades[i].entry_algo,
|
||
|
trades[i].magic,
|
||
|
TimeToString(trades[i].open_time),
|
||
|
trades[i].bars_in_trade,
|
||
|
trades[i].comment);
|
||
|
}
|
||
|
|
||
|
FileClose(handle);
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Calculate performance attribution |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void CMultiTradeReporterV71::CalculatePerformanceAttribution(ManagedTradeV71 &trades[])
|
||
|
{
|
||
|
int trade_count = ArraySize(trades);
|
||
|
if(trade_count == 0) return;
|
||
|
|
||
|
//--- Group trades by strategy
|
||
|
double strategy_returns[];
|
||
|
double benchmark_returns[];
|
||
|
|
||
|
//--- Calculate selection effect (simplified)
|
||
|
double total_return = 0;
|
||
|
double strategy_weighted_return = 0;
|
||
|
|
||
|
for(int i = 0; i < trade_count; i++)
|
||
|
{
|
||
|
double trade_return = trades[i].profit / (trades[i].volume * trades[i].open_price);
|
||
|
total_return += trade_return;
|
||
|
|
||
|
//--- Weight by ML confidence
|
||
|
if(trades[i].ml_enhanced)
|
||
|
{
|
||
|
strategy_weighted_return += trade_return * trades[i].ml_confidence;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
m_attribution.selection_contribution = strategy_weighted_return - total_return / trade_count;
|
||
|
|
||
|
//--- Timing contribution (simplified)
|
||
|
double entry_timing_score = 0;
|
||
|
double exit_timing_score = 0;
|
||
|
|
||
|
for(int i = 0; i < trade_count; i++)
|
||
|
{
|
||
|
//--- Entry timing: compare to average price in next few bars
|
||
|
double avg_price_after = trades[i].open_price; // Simplified
|
||
|
|
||
|
if(trades[i].type == POSITION_TYPE_BUY)
|
||
|
{
|
||
|
entry_timing_score += (avg_price_after - trades[i].open_price) / trades[i].open_price;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
entry_timing_score += (trades[i].open_price - avg_price_after) / trades[i].open_price;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
m_attribution.timing_contribution = entry_timing_score / trade_count;
|
||
|
|
||
|
//--- Allocation effect (position sizing)
|
||
|
double equal_weight_return = total_return / trade_count;
|
||
|
double actual_weighted_return = 0;
|
||
|
double total_risk = 0;
|
||
|
|
||
|
for(int i = 0; i < trade_count; i++)
|
||
|
{
|
||
|
total_risk += trades[i].risk_percent;
|
||
|
}
|
||
|
|
||
|
for(int i = 0; i < trade_count; i++)
|
||
|
{
|
||
|
double weight = trades[i].risk_percent / total_risk;
|
||
|
double trade_return = trades[i].profit / (trades[i].volume * trades[i].open_price);
|
||
|
actual_weighted_return += trade_return * weight;
|
||
|
}
|
||
|
|
||
|
m_attribution.allocation_effect = actual_weighted_return - equal_weight_return;
|
||
|
|
||
|
//--- Currency effect (for non-base currency pairs)
|
||
|
m_attribution.currency_effect = 0; // Simplified
|
||
|
|
||
|
//--- Interaction effect
|
||
|
m_attribution.interaction_effect = 0; // Simplified
|
||
|
|
||
|
//--- Total attribution
|
||
|
m_attribution.total_attribution = m_attribution.selection_contribution +
|
||
|
m_attribution.timing_contribution +
|
||
|
m_attribution.allocation_effect +
|
||
|
m_attribution.currency_effect +
|
||
|
m_attribution.interaction_effect;
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Update performance attribution |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void CMultiTradeReporterV71::UpdatePerformanceAttribution(ManagedTradeV71 &trades[],
|
||
|
PerformanceMetricsV71 &performance)
|
||
|
{
|
||
|
//--- Calculate attribution
|
||
|
CalculatePerformanceAttribution(trades);
|
||
|
|
||
|
//--- Calculate risk attribution
|
||
|
CalculateRiskAttribution(trades);
|
||
|
|
||
|
//--- Store for reporting
|
||
|
m_attribution.strategy_contribution = performance.alpha; // Simplified mapping
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Calculate risk attribution |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void CMultiTradeReporterV71::CalculateRiskAttribution(ManagedTradeV71 &trades[])
|
||
|
{
|
||
|
int trade_count = ArraySize(trades);
|
||
|
if(trade_count == 0) return;
|
||
|
|
||
|
//--- Systematic risk (market beta exposure)
|
||
|
double total_beta_exposure = 0;
|
||
|
for(int i = 0; i < trade_count; i++)
|
||
|
{
|
||
|
total_beta_exposure += trades[i].risk_percent * 0.8; // Assume 0.8 beta
|
||
|
}
|
||
|
m_risk_attribution.systematic_risk = total_beta_exposure / trade_count;
|
||
|
|
||
|
//--- Specific risk (idiosyncratic)
|
||
|
m_risk_attribution.specific_risk = 100 - m_risk_attribution.systematic_risk;
|
||
|
|
||
|
//--- Concentration risk
|
||
|
double max_single_risk = 0;
|
||
|
for(int i = 0; i < trade_count; i++)
|
||
|
{
|
||
|
if(trades[i].risk_percent > max_single_risk)
|
||
|
max_single_risk = trades[i].risk_percent;
|
||
|
}
|
||
|
m_risk_attribution.concentration_risk = max_single_risk;
|
||
|
|
||
|
//--- Correlation risk
|
||
|
double total_correlation_risk = 0;
|
||
|
for(int i = 0; i < trade_count; i++)
|
||
|
{
|
||
|
total_correlation_risk += trades[i].correlation_risk;
|
||
|
}
|
||
|
m_risk_attribution.correlation_risk = total_correlation_risk / trade_count;
|
||
|
|
||
|
//--- Liquidity risk
|
||
|
double avg_liquidity_score = 0;
|
||
|
for(int i = 0; i < trade_count; i++)
|
||
|
{
|
||
|
avg_liquidity_score += trades[i].liquidity_score;
|
||
|
}
|
||
|
avg_liquidity_score /= trade_count;
|
||
|
m_risk_attribution.liquidity_risk = (1.0 - avg_liquidity_score) * 100;
|
||
|
|
||
|
//--- Model risk (based on ML confidence)
|
||
|
double avg_ml_confidence = 0;
|
||
|
int ml_trades = 0;
|
||
|
for(int i = 0; i < trade_count; i++)
|
||
|
{
|
||
|
if(trades[i].ml_enhanced)
|
||
|
{
|
||
|
avg_ml_confidence += trades[i].ml_confidence;
|
||
|
ml_trades++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(ml_trades > 0)
|
||
|
{
|
||
|
avg_ml_confidence /= ml_trades;
|
||
|
m_risk_attribution.model_risk = (1.0 - avg_ml_confidence) * 100;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Analyze trades by strategy |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void CMultiTradeReporterV71::AnalyzeTradesByStrategy(ManagedTradeV71 &trades[], string &output)
|
||
|
{
|
||
|
output = "STRATEGY BREAKDOWN\n";
|
||
|
output += "─────────────────\n";
|
||
|
|
||
|
//--- Group by entry algorithm
|
||
|
struct StrategyGroup
|
||
|
{
|
||
|
string name;
|
||
|
int count;
|
||
|
double profit;
|
||
|
double win_rate;
|
||
|
double avg_r_multiple;
|
||
|
};
|
||
|
|
||
|
StrategyGroup strategies[];
|
||
|
int strategy_count = 0;
|
||
|
int trade_count = ArraySize(trades);
|
||
|
|
||
|
for(int i = 0; i < trade_count; i++)
|
||
|
{
|
||
|
//--- Find or create strategy group
|
||
|
int idx = -1;
|
||
|
for(int j = 0; j < strategy_count; j++)
|
||
|
{
|
||
|
if(strategies[j].name == trades[i].entry_algo)
|
||
|
{
|
||
|
idx = j;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(idx < 0)
|
||
|
{
|
||
|
ArrayResize(strategies, strategy_count + 1);
|
||
|
strategies[strategy_count].name = trades[i].entry_algo;
|
||
|
strategies[strategy_count].count = 0;
|
||
|
strategies[strategy_count].profit = 0;
|
||
|
strategies[strategy_count].win_rate = 0;
|
||
|
strategies[strategy_count].avg_r_multiple = 0;
|
||
|
idx = strategy_count;
|
||
|
strategy_count++;
|
||
|
}
|
||
|
|
||
|
//--- Update metrics
|
||
|
strategies[idx].count++;
|
||
|
strategies[idx].profit += trades[i].profit;
|
||
|
strategies[idx].avg_r_multiple += trades[i].r_multiple;
|
||
|
|
||
|
if(trades[i].profit > 0)
|
||
|
strategies[idx].win_rate++;
|
||
|
}
|
||
|
|
||
|
//--- Calculate averages and format output
|
||
|
for(int i = 0; i < strategy_count; i++)
|
||
|
{
|
||
|
strategies[i].win_rate = (strategies[i].count > 0) ?
|
||
|
strategies[i].win_rate / strategies[i].count * 100 : 0;
|
||
|
strategies[i].avg_r_multiple = (strategies[i].count > 0) ?
|
||
|
strategies[i].avg_r_multiple / strategies[i].count : 0;
|
||
|
|
||
|
output += "\n" + strategies[i].name + ":\n";
|
||
|
output += " Trades: " + IntegerToString(strategies[i].count) + "\n";
|
||
|
output += " P&L: $" + DoubleToString(strategies[i].profit, 2) + "\n";
|
||
|
output += " Win Rate: " + DoubleToString(strategies[i].win_rate, 1) + "%\n";
|
||
|
output += " Avg R-Multiple: " + DoubleToString(strategies[i].avg_r_multiple, 2) + "\n";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Generate JSON report |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void CMultiTradeReporterV71::GenerateJSONReport(ManagedTradeV71 &trades[],
|
||
|
PerformanceMetricsV71 &performance)
|
||
|
{
|
||
|
string timestamp = TimeToString(TimeCurrent(), TIME_DATE|TIME_MINUTES);
|
||
|
StringReplace(timestamp, ":", "_");
|
||
|
StringReplace(timestamp, " ", "_");
|
||
|
|
||
|
string filename = m_report_path + "Report_" + timestamp + ".json";
|
||
|
int handle = FileOpen(filename, FILE_WRITE|FILE_TXT|FILE_ANSI);
|
||
|
|
||
|
if(handle == INVALID_HANDLE) return;
|
||
|
|
||
|
//--- Start JSON
|
||
|
FileWrite(handle, "{");
|
||
|
FileWrite(handle, " \"report_info\": {");
|
||
|
FileWrite(handle, " \"timestamp\": \"" + TimeToString(TimeCurrent()) + "\",");
|
||
|
FileWrite(handle, " \"report_type\": \"" + EnumToString(m_report_type) + "\",");
|
||
|
FileWrite(handle, " \"version\": \"7.1\"");
|
||
|
FileWrite(handle, " },");
|
||
|
|
||
|
//--- Performance metrics
|
||
|
FileWrite(handle, " \"performance\": {");
|
||
|
FileWrite(handle, " \"net_profit\": " + DoubleToString(performance.net_profit, 2) + ",");
|
||
|
FileWrite(handle, " \"total_trades\": " + IntegerToString(performance.total_trades) + ",");
|
||
|
FileWrite(handle, " \"win_rate\": " + DoubleToString(performance.win_rate, 2) + ",");
|
||
|
FileWrite(handle, " \"sharpe_ratio\": " + DoubleToString(performance.sharpe_ratio, 3) + ",");
|
||
|
FileWrite(handle, " \"sortino_ratio\": " + DoubleToString(performance.sortino_ratio, 3) + ",");
|
||
|
FileWrite(handle, " \"information_ratio\": " + DoubleToString(performance.information_ratio, 3) + ",");
|
||
|
FileWrite(handle, " \"max_drawdown\": " + DoubleToString(performance.max_drawdown_percent, 2) + ",");
|
||
|
FileWrite(handle, " \"var_95\": " + DoubleToString(performance.var_95, 2) + ",");
|
||
|
FileWrite(handle, " \"cvar_95\": " + DoubleToString(performance.cvar_95, 2));
|
||
|
FileWrite(handle, " },");
|
||
|
|
||
|
//--- Trades array
|
||
|
FileWrite(handle, " \"trades\": [");
|
||
|
|
||
|
int trade_count = ArraySize(trades);
|
||
|
for(int i = 0; i < trade_count; i++)
|
||
|
{
|
||
|
FileWrite(handle, " {");
|
||
|
FileWrite(handle, " \"ticket\": " + IntegerToString(trades[i].ticket) + ",");
|
||
|
FileWrite(handle, " \"symbol\": \"" + trades[i].symbol + "\",");
|
||
|
FileWrite(handle, " \"type\": \"" + ((trades[i].type == POSITION_TYPE_BUY) ? "BUY" : "SELL") + "\",");
|
||
|
FileWrite(handle, " \"volume\": " + DoubleToString(trades[i].volume, 2) + ",");
|
||
|
FileWrite(handle, " \"profit\": " + DoubleToString(trades[i].profit, 2) + ",");
|
||
|
FileWrite(handle, " \"risk_percent\": " + DoubleToString(trades[i].risk_percent, 2) + ",");
|
||
|
FileWrite(handle, " \"r_multiple\": " + DoubleToString(trades[i].r_multiple, 2) + ",");
|
||
|
FileWrite(handle, " \"ml_confidence\": " + DoubleToString(trades[i].ml_confidence, 3));
|
||
|
FileWrite(handle, " }" + ((i < trade_count - 1) ? "," : ""));
|
||
|
}
|
||
|
|
||
|
FileWrite(handle, " ]");
|
||
|
FileWrite(handle, "}");
|
||
|
|
||
|
FileClose(handle);
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Generate HTML report |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void CMultiTradeReporterV71::GenerateHTMLReport(ManagedTradeV71 &trades[],
|
||
|
PerformanceMetricsV71 &performance)
|
||
|
{
|
||
|
string timestamp = TimeToString(TimeCurrent(), TIME_DATE|TIME_MINUTES);
|
||
|
StringReplace(timestamp, ":", "_");
|
||
|
StringReplace(timestamp, " ", "_");
|
||
|
|
||
|
string filename = m_report_path + "Report_" + timestamp + ".html";
|
||
|
int handle = FileOpen(filename, FILE_WRITE|FILE_TXT|FILE_ANSI);
|
||
|
|
||
|
if(handle == INVALID_HANDLE) return;
|
||
|
|
||
|
//--- HTML header
|
||
|
FileWrite(handle, "<!DOCTYPE html>");
|
||
|
FileWrite(handle, "<html>");
|
||
|
FileWrite(handle, "<head>");
|
||
|
FileWrite(handle, "<title>ERMT 7.1 Institutional Report</title>");
|
||
|
FileWrite(handle, "<style>");
|
||
|
FileWrite(handle, "body { font-family: Arial, sans-serif; background-color: #1e1e1e; color: #e0e0e0; }");
|
||
|
FileWrite(handle, "h1, h2 { color: #00bcd4; }");
|
||
|
FileWrite(handle, "table { border-collapse: collapse; width: 100%; margin: 20px 0; }");
|
||
|
FileWrite(handle, "th, td { border: 1px solid #333; padding: 8px; text-align: left; }");
|
||
|
FileWrite(handle, "th { background-color: #2c2c2c; color: #00bcd4; }");
|
||
|
FileWrite(handle, "tr:nth-child(even) { background-color: #252525; }");
|
||
|
FileWrite(handle, ".profit { color: #4caf50; }");
|
||
|
FileWrite(handle, ".loss { color: #f44336; }");
|
||
|
FileWrite(handle, ".metric-card { background-color: #2c2c2c; padding: 15px; margin: 10px; border-radius: 5px; display: inline-block; }");
|
||
|
FileWrite(handle, "</style>");
|
||
|
FileWrite(handle, "</head>");
|
||
|
FileWrite(handle, "<body>");
|
||
|
|
||
|
//--- Title
|
||
|
FileWrite(handle, "<h1>ERMT 7.1 Institutional Trading Report</h1>");
|
||
|
FileWrite(handle, "<p>Generated: " + TimeToString(TimeCurrent()) + "</p>");
|
||
|
|
||
|
//--- Key metrics cards
|
||
|
FileWrite(handle, "<div>");
|
||
|
FileWrite(handle, "<div class='metric-card'>");
|
||
|
FileWrite(handle, "<h3>Net P&L</h3>");
|
||
|
FileWrite(handle, "<p class='" + ((performance.net_profit >= 0) ? "profit" : "loss") + "'>$" +
|
||
|
DoubleToString(performance.net_profit, 2) + "</p>");
|
||
|
FileWrite(handle, "</div>");
|
||
|
|
||
|
FileWrite(handle, "<div class='metric-card'>");
|
||
|
FileWrite(handle, "<h3>Sharpe Ratio</h3>");
|
||
|
FileWrite(handle, "<p>" + DoubleToString(performance.sharpe_ratio, 3) + "</p>");
|
||
|
FileWrite(handle, "</div>");
|
||
|
|
||
|
FileWrite(handle, "<div class='metric-card'>");
|
||
|
FileWrite(handle, "<h3>Win Rate</h3>");
|
||
|
FileWrite(handle, "<p>" + DoubleToString(performance.win_rate, 1) + "%</p>");
|
||
|
FileWrite(handle, "</div>");
|
||
|
|
||
|
FileWrite(handle, "<div class='metric-card'>");
|
||
|
FileWrite(handle, "<h3>Max Drawdown</h3>");
|
||
|
FileWrite(handle, "<p class='loss'>" + DoubleToString(performance.max_drawdown_percent, 2) + "%</p>");
|
||
|
FileWrite(handle, "</div>");
|
||
|
FileWrite(handle, "</div>");
|
||
|
|
||
|
//--- Trades table
|
||
|
FileWrite(handle, "<h2>Active Positions</h2>");
|
||
|
FileWrite(handle, "<table>");
|
||
|
FileWrite(handle, "<tr><th>Symbol</th><th>Type</th><th>Volume</th><th>Entry</th><th>P&L</th><th>Risk%</th><th>R-Multiple</th></tr>");
|
||
|
|
||
|
int trade_count = ArraySize(trades);
|
||
|
for(int i = 0; i < trade_count; i++)
|
||
|
{
|
||
|
string pl_class = (trades[i].profit >= 0) ? "profit" : "loss";
|
||
|
FileWrite(handle, "<tr>");
|
||
|
FileWrite(handle, "<td>" + trades[i].symbol + "</td>");
|
||
|
FileWrite(handle, "<td>" + ((trades[i].type == POSITION_TYPE_BUY) ? "BUY" : "SELL") + "</td>");
|
||
|
FileWrite(handle, "<td>" + DoubleToString(trades[i].volume, 2) + "</td>");
|
||
|
FileWrite(handle, "<td>" + DoubleToString(trades[i].open_price, 5) + "</td>");
|
||
|
FileWrite(handle, "<td class='" + pl_class + "'>$" + DoubleToString(trades[i].profit, 2) + "</td>");
|
||
|
FileWrite(handle, "<td>" + DoubleToString(trades[i].risk_percent, 2) + "%</td>");
|
||
|
FileWrite(handle, "<td class='" + pl_class + "'>" + DoubleToString(trades[i].r_multiple, 2) + "</td>");
|
||
|
FileWrite(handle, "</tr>");
|
||
|
}
|
||
|
|
||
|
FileWrite(handle, "</table>");
|
||
|
|
||
|
//--- Footer
|
||
|
FileWrite(handle, "<p style='text-align: center; color: #666; margin-top: 50px;'>ERMT 7.1 - Institutional Risk Management System</p>");
|
||
|
FileWrite(handle, "</body>");
|
||
|
FileWrite(handle, "</html>");
|
||
|
|
||
|
FileClose(handle);
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Check compliance |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void CMultiTradeReporterV71::CheckCompliance(ManagedTradeV71 &trades[],
|
||
|
ComplianceMetrics &metrics)
|
||
|
{
|
||
|
//--- Reset metrics
|
||
|
metrics.violations_count = 0;
|
||
|
metrics.max_position_breach = 0;
|
||
|
metrics.max_drawdown_breach = 0;
|
||
|
metrics.max_var_breach = 0;
|
||
|
metrics.unauthorized_trades = 0;
|
||
|
ArrayResize(metrics.violation_details, 0);
|
||
|
|
||
|
//--- Check position limits
|
||
|
double total_exposure = 0;
|
||
|
int trade_count = ArraySize(trades);
|
||
|
|
||
|
for(int i = 0; i < trade_count; i++)
|
||
|
{
|
||
|
total_exposure += trades[i].risk_percent;
|
||
|
|
||
|
//--- Check individual position limit (example: 2% max)
|
||
|
if(trades[i].risk_percent > 2.0)
|
||
|
{
|
||
|
metrics.violations_count++;
|
||
|
metrics.max_position_breach = MathMax(metrics.max_position_breach,
|
||
|
trades[i].risk_percent - 2.0);
|
||
|
|
||
|
int size = ArraySize(metrics.violation_details);
|
||
|
ArrayResize(metrics.violation_details, size + 1);
|
||
|
metrics.violation_details[size] = "Position limit breach: " +
|
||
|
trades[i].symbol + " at " +
|
||
|
DoubleToString(trades[i].risk_percent, 2) + "%";
|
||
|
}
|
||
|
|
||
|
//--- Check authorized magic numbers
|
||
|
if(trades[i].magic < 10000 || trades[i].magic > 99999)
|
||
|
{
|
||
|
metrics.unauthorized_trades++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//--- Check total exposure limit (example: 6% max)
|
||
|
if(total_exposure > 6.0)
|
||
|
{
|
||
|
metrics.violations_count++;
|
||
|
int size = ArraySize(metrics.violation_details);
|
||
|
ArrayResize(metrics.violation_details, size + 1);
|
||
|
metrics.violation_details[size] = "Total exposure limit breach: " +
|
||
|
DoubleToString(total_exposure, 2) + "%";
|
||
|
}
|
||
|
|
||
|
//--- Update compliance tracking
|
||
|
m_compliance = metrics;
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Generate VaR report |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void CMultiTradeReporterV71::GenerateVaRReport(ManagedTradeV71 &trades[],
|
||
|
double var, double cvar)
|
||
|
{
|
||
|
string timestamp = TimeToString(TimeCurrent(), TIME_DATE|TIME_MINUTES);
|
||
|
StringReplace(timestamp, ":", "_");
|
||
|
StringReplace(timestamp, " ", "_");
|
||
|
|
||
|
string filename = m_report_path + "VaR_Report_" + timestamp + ".txt";
|
||
|
int handle = FileOpen(filename, FILE_WRITE|FILE_TXT|FILE_ANSI);
|
||
|
|
||
|
if(handle == INVALID_HANDLE) return;
|
||
|
|
||
|
FileWrite(handle, "VALUE AT RISK REPORT");
|
||
|
FileWrite(handle, "===================");
|
||
|
FileWrite(handle, "");
|
||
|
FileWrite(handle, "Report Date: " + TimeToString(TimeCurrent()));
|
||
|
FileWrite(handle, "");
|
||
|
FileWrite(handle, "Portfolio VaR (95%): " + DoubleToString(var, 3) + "%");
|
||
|
FileWrite(handle, "Portfolio CVaR (95%): " + DoubleToString(cvar, 3) + "%");
|
||
|
FileWrite(handle, "");
|
||
|
FileWrite(handle, "VaR BY POSITION:");
|
||
|
FileWrite(handle, "----------------");
|
||
|
|
||
|
int trade_count = ArraySize(trades);
|
||
|
double total_var = 0;
|
||
|
|
||
|
for(int i = 0; i < trade_count; i++)
|
||
|
{
|
||
|
FileWrite(handle, trades[i].symbol + ": " +
|
||
|
DoubleToString(trades[i].var_contribution, 3) + "%");
|
||
|
total_var += trades[i].var_contribution;
|
||
|
}
|
||
|
|
||
|
FileWrite(handle, "");
|
||
|
FileWrite(handle, "Total VaR Contribution: " + DoubleToString(total_var, 3) + "%");
|
||
|
FileWrite(handle, "Diversification Benefit: " + DoubleToString(total_var - var, 3) + "%");
|
||
|
|
||
|
FileClose(handle);
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Set export formats |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void CMultiTradeReporterV71::SetExportFormats(bool csv, bool html, bool json, bool fix)
|
||
|
{
|
||
|
m_csv_export = csv;
|
||
|
m_html_export = html;
|
||
|
m_json_export = json;
|
||
|
m_fix_export = fix;
|
||
|
}
|
||
|
|
||
|
#endif // MULTI_TRADE_REPORTER_V71_MQH
|