Overview To fully integrate the enhanced external trade management system, updates are required to 5 out of 7 existing modules. The updates maintain backward compatibility while adding new functionality for external trade handling. Module Update Requirements 🟢 No Updates Required (2 modules) TechnicalAnalysis.mqh - Already provides necessary calculations EntrySystem.mqh - Only handles EA's own entry signals 🟡 Minor Updates (2 modules) DataTypes.mqh - Add external trade structures and fields Utilities.mqh - Enhanced logging for external trades 🟠 Moderate Updates (3 modules) RiskManager.mqh - Enhanced risk enforcement methods TradeManager.mqh - Improved stop management for externals Dashboard.mqh - Display external trade information Integration Steps Phase 1: Data Structures (DataTypes.mqh) Add ENUM_EXTERNAL_STATUS enumeration Extend ManagedTrade structure with external-specific fields Add ExternalTradeStats structure for metrics Update DashboardConfig with show_external flag Key additions: external_status - Track state of external trade source_name - Identify where trade came from stops_modified - Track if we modified the trade original_sl/tp - Store original values for comparison Phase 2: Risk Management (RiskManager.mqh) Add EnforceRiskRulesEnhanced() method Implement GetExternalExposure() for risk aggregation Add UpdateExternalStats() for tracking Enhance ValidateAndAdjustRiskExternal() method Key features: Separate risk calculation for external trades Cache mechanism for performance Statistical tracking of external positions Smart risk adjustment without closing trades Phase 3: Trade Management (TradeManager.mqh) Add ApplyDefaultStopsEnhanced() with better logic Implement OverrideExternalStops() with smart override Create ManageExternalTrade() with different rules Add ApplyBreakevenExternal() with wider triggers Key features: Smart stop override (only improve, never worsen) Different management rules for external trades Respect minimum broker distances Track modification success/failure rates Phase 4: User Interface (Dashboard.mqh) Add CreateExternalSection() for display area Implement UpdateExternalSection() for real-time updates Add SetCustomText() for flexible display Create ShowExternalTrades() toggle method Key features: Real-time external trade count and risk Color-coded risk warnings List of active external positions Modification statistics display Phase 5: Logging (Utilities.mqh) Add LogExternalTrade() for detailed event logging Create separate CSV log for external trades Enhance GenerateReportEnhanced() with external section Add IdentifyTradeSource() for magic number interpretation Key features: Separate CSV log for external trade events Detailed tracking of all modifications Source identification from magic numbers Enhanced reporting with external statistics
956 lines
No EOL
40 KiB
MQL5
956 lines
No EOL
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 |