1044 lines
82 KiB
MQL5
1044 lines
82 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| Enhanced Risk Management Overlay EA v4.0 |
|
|
//| Complete Fixed Implementation |
|
|
//| With MA Entry System & External Trade Management |
|
|
//+------------------------------------------------------------------+
|
|
#property version "4.00"
|
|
#property strict
|
|
#property description "Professional risk management system with MA entry and external trade management"
|
|
|
|
#include <Trade/Trade.mqh>
|
|
#include <Trade/PositionInfo.mqh>
|
|
#include <Trade/OrderInfo.mqh>
|
|
#include <Trade/DealInfo.mqh>
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| ENUMERATIONS |
|
|
//+------------------------------------------------------------------+
|
|
|
|
enum ENUM_TP_STRATEGY
|
|
{
|
|
TP_STATIC = 0, // Static risk:reward ratio
|
|
TP_TRAILING = 1, // Dynamic trailing take profit
|
|
TP_PARTIAL = 2, // Multi-level partial profits
|
|
TP_TECHNICAL = 3, // Technical level-based exits
|
|
TP_VOLATILITY = 4, // ATR-adjusted targets
|
|
TP_ADAPTIVE = 5, // Machine learning-based selection
|
|
TP_HYBRID = 6 // Combination of multiple strategies
|
|
};
|
|
|
|
enum ENUM_TP_STATUS
|
|
{
|
|
TP_NONE = 0, // No partial closes yet
|
|
TP_FIRST = 1, // First target hit (33%)
|
|
TP_SECOND = 2, // Second target hit (66%)
|
|
TP_THIRD = 3, // Third target hit (80%)
|
|
TP_FINAL = 4 // Only final portion remains
|
|
};
|
|
|
|
enum ENUM_POSITION_SIZING
|
|
{
|
|
PS_FIXED_LOTS = 0, // Fixed lot size
|
|
PS_RISK_PERCENT = 1, // Percentage of equity at risk
|
|
PS_CAPITAL_PERCENT = 2, // Percentage of total capital
|
|
PS_ATR_BASED = 3, // Volatility-adjusted sizing
|
|
PS_KELLY = 4 // Kelly Criterion sizing
|
|
};
|
|
|
|
enum ENUM_MA_ENTRY_TYPE
|
|
{
|
|
MA_DISABLED = 0, // No MA entry (external only)
|
|
MA_SIMPLE_CROSS = 1, // Fast/Slow MA crossover
|
|
MA_TRIPLE_CROSS = 2, // Three MA system
|
|
MA_PULLBACK = 3, // MA pullback entry
|
|
MA_MOMENTUM = 4 // MA with momentum confirmation
|
|
};
|
|
|
|
enum ENUM_TECHNICAL_LEVEL
|
|
{
|
|
TECH_FIBONACCI = 0, // Fibonacci retracements/extensions
|
|
TECH_PIVOT_POINTS = 1, // Daily/Weekly pivot points
|
|
TECH_MOVING_AVG = 2, // Dynamic moving averages
|
|
TECH_ROUND_NUMBERS = 3, // Psychological levels
|
|
TECH_VWAP = 4, // Volume-weighted average price
|
|
TECH_SUPPORT_RES = 5, // Historical S/R levels
|
|
TECH_SUPPLY_DEMAND = 6 // Supply/Demand zones
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| STRUCTURES |
|
|
//+------------------------------------------------------------------+
|
|
|
|
struct TechnicalLevel
|
|
{
|
|
double price;
|
|
ENUM_TECHNICAL_LEVEL type;
|
|
double score;
|
|
double zone_width;
|
|
string description;
|
|
datetime last_touch;
|
|
int touch_count;
|
|
};
|
|
|
|
struct RiskData
|
|
{
|
|
double atr_value;
|
|
double sr_support;
|
|
double sr_resistance;
|
|
double sar_value;
|
|
double trail_stop;
|
|
double trail_tp;
|
|
double volatility_factor;
|
|
double market_volatility;
|
|
double trend_strength;
|
|
TechnicalLevel technical_levels[30];
|
|
int technical_count;
|
|
double best_technical_target;
|
|
datetime last_update;
|
|
};
|
|
|
|
struct TradeInfo
|
|
{
|
|
ulong ticket;
|
|
double open_price;
|
|
double original_volume;
|
|
double current_volume;
|
|
double current_sl;
|
|
double current_tp;
|
|
double best_profit;
|
|
double worst_drawdown;
|
|
datetime open_time;
|
|
datetime breakeven_time;
|
|
ENUM_TP_STATUS tp_status;
|
|
ENUM_TP_STRATEGY tp_strategy;
|
|
bool breakeven_set;
|
|
double entry_atr;
|
|
double risk_amount;
|
|
string entry_reason;
|
|
RiskData risk_data;
|
|
};
|
|
|
|
struct StrategyPerformance
|
|
{
|
|
ENUM_TP_STRATEGY strategy;
|
|
int trades_count;
|
|
double total_profit;
|
|
double total_loss;
|
|
double avg_profit;
|
|
double avg_win;
|
|
double avg_loss;
|
|
double max_drawdown;
|
|
double win_rate;
|
|
double profit_factor;
|
|
double expectancy;
|
|
double sharpe_ratio;
|
|
double recovery_factor;
|
|
double score;
|
|
double trade_profits[100];
|
|
int profit_index;
|
|
datetime last_update;
|
|
};
|
|
|
|
struct MarketAnalysis
|
|
{
|
|
double trend_direction;
|
|
double volatility_regime;
|
|
double momentum_score;
|
|
bool news_upcoming;
|
|
datetime last_analysis;
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| INPUT PARAMETERS |
|
|
//+------------------------------------------------------------------+
|
|
|
|
input group "=== ENTRY SYSTEMS ==="
|
|
input ENUM_MA_ENTRY_TYPE MAEntryType = MA_SIMPLE_CROSS; // Moving Average Entry Type
|
|
input bool EnableContrarian = false; // Enable Contrarian Entry
|
|
input bool ManageExistingTrades = true; // Manage External Trades
|
|
input bool UseOptimizedParameters = true; // Use Optimized Default Parameters
|
|
|
|
input group "=== MOVING AVERAGE ENTRY SETTINGS ==="
|
|
input int MA_Fast_Period = 20; // Fast MA Period
|
|
input int MA_Slow_Period = 50; // Slow MA Period
|
|
input int MA_Filter_Period = 200; // Trend Filter MA Period
|
|
input ENUM_MA_METHOD MA_Method = MODE_EMA; // MA Calculation Method
|
|
input ENUM_APPLIED_PRICE MA_Price = PRICE_CLOSE; // MA Applied Price
|
|
input double MA_MinDistance = 10; // Min distance between MAs (points)
|
|
input bool MA_RequireMomentum = true; // Require momentum confirmation
|
|
input int RSI_Period = 14; // RSI Period for momentum
|
|
input double RSI_BuyLevel = 50; // RSI Buy threshold
|
|
input double RSI_SellLevel = 50; // RSI Sell threshold
|
|
|
|
input group "=== CONTRARIAN ENTRY SETTINGS ==="
|
|
input int ConsecutiveBars = 3; // Number of consecutive bars
|
|
input double MinBarSize = 100; // Minimum bar size in points
|
|
input double MaxBarSize = 500; // Maximum bar size in points
|
|
input bool RequireVolumeConfirmation = true; // Require volume confirmation
|
|
input double VolumeMultiplier = 1.2; // Volume multiplier threshold
|
|
|
|
input group "=== POSITION SIZING ==="
|
|
input ENUM_POSITION_SIZING PositionSizingMode = PS_RISK_PERCENT;
|
|
input double FixedLotSize = 0.1; // Fixed lot size
|
|
input double RiskPercent = 1.5; // Risk per trade (%)
|
|
input double MaxRiskPercent = 3.0; // Maximum risk per trade (%)
|
|
input double CapitalPercent = 10.0; // Capital allocation (%)
|
|
input double KellyFraction = 0.25; // Kelly fraction (25% = quarter Kelly)
|
|
input int MaxPositions = 3; // Maximum simultaneous positions
|
|
input int TradingMagic = 12345; // Magic number for trades
|
|
|
|
input group "=== TAKE PROFIT STRATEGY ==="
|
|
input bool EnableAdvancedTP = true; // Enable advanced TP management
|
|
input ENUM_TP_STRATEGY TakeProfitMode = TP_ADAPTIVE; // Take profit strategy
|
|
input double BaseTPRatio = 2.0; // Base TP ratio (risk:reward)
|
|
input double TrailingTPStart = 1.0; // Start trailing after X:1
|
|
input double TrailingTPStep = 0.3; // Trailing step (ATR multiplier)
|
|
input double PartialTP1Ratio = 1.0; // First partial TP (1:1)
|
|
input double PartialTP2Ratio = 2.0; // Second partial TP (2:1)
|
|
input double PartialTP3Ratio = 3.0; // Third partial TP (3:1)
|
|
input double PartialClosePercent1 = 30.0; // First partial close %
|
|
input double PartialClosePercent2 = 30.0; // Second partial close %
|
|
input double PartialClosePercent3 = 20.0; // Third partial close %
|
|
input double VolatilityTPMultiplier = 1.5; // Volatility TP adjustment
|
|
input int AdaptivePeriod = 20; // Adaptive evaluation period
|
|
|
|
input group "=== TECHNICAL ANALYSIS ==="
|
|
input bool UseFibonacci = true; // Use Fibonacci levels
|
|
input bool UsePivotPoints = true; // Use Pivot Points
|
|
input bool UseMovingAverages = true; // Use MA levels
|
|
input bool UseRoundNumbers = true; // Use Round Numbers
|
|
input bool UseVWAP = true; // Use VWAP
|
|
input bool UseSupplyDemand = true; // Use Supply/Demand zones
|
|
input double MinConfluenceScore = 3.0; // Minimum confluence score
|
|
input double TechnicalTolerancePoints = 20; // Technical level tolerance
|
|
input int TechnicalLookbackBars = 100; // Technical analysis lookback
|
|
input int FibLookbackBars = 100; // Fibonacci lookback period
|
|
input string RoundNumberStep = "50"; // Round number increment
|
|
|
|
input group "=== RISK MANAGEMENT ==="
|
|
input bool EnableATRSizing = true; // ATR-based position sizing
|
|
input bool EnableSRTrails = true; // Support/Resistance trails
|
|
input bool EnableSARExits = true; // Parabolic SAR exits
|
|
input bool EnableBreakeven = true; // Breakeven management
|
|
input double BreakevenTrigger = 1.0; // Move to BE after X:1
|
|
input double BreakevenBuffer = 5; // BE buffer in points
|
|
|
|
input group "=== ATR SETTINGS ==="
|
|
input int ATR_Period = 14; // ATR calculation period
|
|
input double ATR_Multiplier = 2.0; // ATR stop loss multiplier
|
|
input double ATR_TPMultiplier = 3.0; // ATR take profit multiplier
|
|
input double MinLotSize = 0.01; // Minimum lot size
|
|
input double MaxLotSize = 10.0; // Maximum lot size
|
|
|
|
input group "=== SUPPORT/RESISTANCE ==="
|
|
input int SR_LookbackPeriod = 150; // S/R lookback period
|
|
input double SR_MinDistance = 100; // Minimum S/R distance
|
|
input int SR_TouchCount = 3; // Minimum touches for S/R
|
|
input double SR_TolerancePoints = 30; // S/R clustering tolerance
|
|
input double SR_ZoneWidth = 20; // S/R zone width
|
|
|
|
input group "=== PARABOLIC SAR ==="
|
|
input double SAR_Step = 0.02; // SAR step
|
|
input double SAR_Maximum = 0.2; // SAR maximum
|
|
|
|
input group "=== TRADE MANAGEMENT ==="
|
|
input int MagicNumberFilter = 0; // Filter by magic (0 = all)
|
|
input int MaxHoldingPeriod = 0; // Max holding minutes (0 = off)
|
|
input double MaxDrawdownPercent = 5.0; // Max portfolio drawdown %
|
|
input bool CloseOnFridayEnd = true; // Close before weekend
|
|
input bool EnableNewsFilter = true; // Avoid news events
|
|
input int NewsBufferMinutes = 30; // Minutes before/after news
|
|
|
|
input group "=== PERFORMANCE & LOGGING ==="
|
|
input bool EnableLogging = true; // Detailed logging
|
|
input bool EnableDashboard = true; // Performance dashboard
|
|
input bool SendAlerts = false; // Send alerts
|
|
input bool SaveReports = true; // Save performance reports
|
|
input int ReportInterval = 1440; // Report interval (minutes)
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| GLOBAL VARIABLES |
|
|
//+------------------------------------------------------------------+
|
|
|
|
CTrade trade;
|
|
CPositionInfo posInfo;
|
|
COrderInfo orderInfo;
|
|
CDealInfo dealInfo;
|
|
|
|
TradeInfo managed_trades[];
|
|
StrategyPerformance strategy_performance[7];
|
|
MarketAnalysis market_analysis;
|
|
|
|
double account_start_balance;
|
|
datetime last_risk_check;
|
|
datetime last_bar_time;
|
|
datetime last_strategy_eval;
|
|
datetime last_report_time;
|
|
ENUM_TP_STRATEGY current_best_strategy;
|
|
|
|
// Performance tracking
|
|
double session_profit = 0;
|
|
double session_loss = 0;
|
|
int session_wins = 0;
|
|
int session_losses = 0;
|
|
double peak_balance = 0;
|
|
double current_drawdown = 0;
|
|
double max_historical_drawdown = 0;
|
|
|
|
// Trade management
|
|
datetime last_trade_time = 0;
|
|
int consecutive_losses = 0;
|
|
double current_risk_multiplier = 1.0;
|
|
|
|
// Indicator handles
|
|
int g_ma_fast_handle = INVALID_HANDLE;
|
|
int g_ma_slow_handle = INVALID_HANDLE;
|
|
int g_ma_filter_handle = INVALID_HANDLE;
|
|
int g_atr_handle = INVALID_HANDLE;
|
|
int g_rsi_handle = INVALID_HANDLE;
|
|
int g_sar_handle = INVALID_HANDLE;
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert initialization function |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
// Set trade parameters
|
|
trade.SetExpertMagicNumber(TradingMagic);
|
|
trade.SetDeviationInPoints(50);
|
|
trade.SetTypeFilling(ORDER_FILLING_RETURN);
|
|
trade.SetAsyncMode(false);
|
|
|
|
// Create indicator handles
|
|
g_atr_handle = iATR(_Symbol, PERIOD_CURRENT, ATR_Period);
|
|
g_sar_handle = iSAR(_Symbol, PERIOD_CURRENT, SAR_Step, SAR_Maximum);
|
|
|
|
if(MAEntryType != MA_DISABLED)
|
|
{
|
|
g_ma_fast_handle = iMA(_Symbol, PERIOD_CURRENT, MA_Fast_Period, 0, MA_Method, MA_Price);
|
|
g_ma_slow_handle = iMA(_Symbol, PERIOD_CURRENT, MA_Slow_Period, 0, MA_Method, MA_Price);
|
|
if(MA_Filter_Period > 0)
|
|
g_ma_filter_handle = iMA(_Symbol, PERIOD_CURRENT, MA_Filter_Period, 0, MA_Method, MA_Price);
|
|
}
|
|
if(MA_RequireMomentum)
|
|
g_rsi_handle = iRSI(_Symbol, PERIOD_CURRENT, RSI_Period, PRICE_CLOSE);
|
|
// Validate handles
|
|
if(g_atr_handle == INVALID_HANDLE || g_sar_handle == INVALID_HANDLE ||
|
|
(MAEntryType != MA_DISABLED && (g_ma_fast_handle == INVALID_HANDLE || g_ma_slow_handle == INVALID_HANDLE)))
|
|
{
|
|
Print("Error creating indicator handles");
|
|
return(INIT_FAILED);
|
|
}
|
|
// Initialize account variables
|
|
account_start_balance = AccountInfoDouble(ACCOUNT_BALANCE);
|
|
peak_balance = account_start_balance;
|
|
last_risk_check = TimeCurrent();
|
|
last_bar_time = 0;
|
|
last_strategy_eval = TimeCurrent();
|
|
last_report_time = TimeCurrent();
|
|
current_best_strategy = TakeProfitMode;
|
|
// Initialize strategy performance tracking
|
|
InitializeStrategyPerformance();
|
|
// Initialize market analysis
|
|
market_analysis.trend_direction = 0;
|
|
market_analysis.volatility_regime = 1.0;
|
|
market_analysis.momentum_score = 0;
|
|
market_analysis.news_upcoming = false;
|
|
market_analysis.last_analysis = 0;
|
|
// Display initialization info
|
|
Print("=== ENHANCED RISK MANAGEMENT OVERLAY v3.0 ===");
|
|
Print("Account Balance: $", account_start_balance);
|
|
Print("Entry Mode: ", GetEntryModeDescription());
|
|
Print("Risk Management: ", EnumToString(PositionSizingMode), " @ ", RiskPercent, "%");
|
|
Print("Take Profit: ", EnumToString(TakeProfitMode));
|
|
Print("Max Positions: ", MaxPositions);
|
|
if(EnableDashboard)
|
|
{
|
|
CreateDashboard();
|
|
}
|
|
return(INIT_SUCCEEDED);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert deinitialization function |
|
|
//+------------------------------------------------------------------+
|
|
void OnDeinit(const int reason)
|
|
{
|
|
// Release indicator handles
|
|
if(g_atr_handle != INVALID_HANDLE) IndicatorRelease(g_atr_handle);
|
|
if(g_sar_handle != INVALID_HANDLE) IndicatorRelease(g_sar_handle);
|
|
if(g_ma_fast_handle != INVALID_HANDLE) IndicatorRelease(g_ma_fast_handle);
|
|
if(g_ma_slow_handle != INVALID_HANDLE) IndicatorRelease(g_ma_slow_handle);
|
|
if(g_ma_filter_handle != INVALID_HANDLE) IndicatorRelease(g_ma_filter_handle);
|
|
if(g_rsi_handle != INVALID_HANDLE) IndicatorRelease(g_rsi_handle);
|
|
// Cleanup actions
|
|
if(EnableDashboard)
|
|
{
|
|
DestroyDashboard();
|
|
}
|
|
Print("=== ENHANCED RISK MANAGEMENT OVERLAY v3.0 - DEINITIALIZED ===");
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert tick function |
|
|
//+------------------------------------------------------------------+
|
|
void OnTick()
|
|
{
|
|
// Risk management checks
|
|
ManageRisk();
|
|
|
|
// Trading strategy execution
|
|
ExecuteTradingStrategies();
|
|
|
|
// Update dashboard
|
|
if(EnableDashboard)
|
|
{
|
|
UpdateDashboard();
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Get ATR value |
|
|
//+------------------------------------------------------------------+
|
|
double GetATRValue(int shift = 0)
|
|
{
|
|
double buffer[1];
|
|
if(CopyBuffer(g_atr_handle, 0, shift, 1, buffer) <= 0)
|
|
return 0;
|
|
return buffer[0];
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Get SAR value |
|
|
//+------------------------------------------------------------------+
|
|
double GetSARValue(int shift = 0)
|
|
{
|
|
double buffer[1];
|
|
if(CopyBuffer(g_sar_handle, 0, shift, 1, buffer) <= 0)
|
|
return 0;
|
|
return buffer[0];
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Modular risk management stubs (implement as needed) |
|
|
//+------------------------------------------------------------------+
|
|
void ApplyTakeProfitStrategy(TradeInfo &trade_info) {}
|
|
void ApplyBreakevenManagement(TradeInfo &trade_info) {}
|
|
void ApplyTrailingStop(TradeInfo &trade_info) {}
|
|
void CheckSARExits(TradeInfo &trade_info) {}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Manage risk for open trades |
|
|
//+------------------------------------------------------------------+
|
|
void ManageRisk()
|
|
{
|
|
// Update managed trades list first
|
|
UpdateManagedTrades();
|
|
|
|
// Iterate through managed trades
|
|
for(int i = ArraySize(managed_trades) - 1; i >= 0; i--)
|
|
{
|
|
if(!posInfo.SelectByTicket(managed_trades[i].ticket))
|
|
{
|
|
// Position closed, remove from array
|
|
RemoveTradeFromArray(i);
|
|
continue;
|
|
}
|
|
|
|
// Update risk data
|
|
UpdateRiskData(managed_trades[i]);
|
|
|
|
// Apply various risk management techniques
|
|
if(EnableAdvancedTP)
|
|
ApplyTakeProfitStrategy(managed_trades[i]);
|
|
|
|
if(EnableBreakeven)
|
|
ApplyBreakevenManagement(managed_trades[i]);
|
|
|
|
if(EnableSRTrails)
|
|
ApplyTrailingStop(managed_trades[i]);
|
|
|
|
if(EnableSARExits)
|
|
CheckSARExits(managed_trades[i]);
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Update managed trades array |
|
|
//+------------------------------------------------------------------+
|
|
void UpdateManagedTrades()
|
|
{
|
|
// Check for new positions to manage
|
|
for(int i = 0; i < PositionsTotal(); i++)
|
|
{
|
|
if(posInfo.SelectByIndex(i))
|
|
{
|
|
if(posInfo.Symbol() == _Symbol)
|
|
{
|
|
bool should_manage = false;
|
|
|
|
// Check if we should manage this position
|
|
if(posInfo.Magic() == TradingMagic)
|
|
should_manage = true;
|
|
else if(ManageExistingTrades && (MagicNumberFilter == 0 || posInfo.Magic() == MagicNumberFilter))
|
|
should_manage = true;
|
|
|
|
if(should_manage && !IsTradeInArray(posInfo.Ticket()))
|
|
{
|
|
AddExternalTrade(posInfo.Ticket());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Check if trade is already in managed array |
|
|
//+------------------------------------------------------------------+
|
|
bool IsTradeInArray(ulong ticket)
|
|
{
|
|
for(int i = 0; i < ArraySize(managed_trades); i++)
|
|
{
|
|
if(managed_trades[i].ticket == ticket)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Add external trade to managed array |
|
|
//+------------------------------------------------------------------+
|
|
void AddExternalTrade(ulong ticket)
|
|
{
|
|
if(!posInfo.SelectByTicket(ticket)) return;
|
|
|
|
TradeInfo new_trade;
|
|
new_trade.ticket = ticket;
|
|
new_trade.open_price = posInfo.PriceOpen();
|
|
new_trade.original_volume = posInfo.Volume();
|
|
new_trade.current_volume = posInfo.Volume();
|
|
new_trade.current_sl = posInfo.StopLoss();
|
|
new_trade.current_tp = posInfo.TakeProfit();
|
|
new_trade.best_profit = posInfo.Profit();
|
|
new_trade.worst_drawdown = 0;
|
|
new_trade.open_time = posInfo.Time();
|
|
new_trade.breakeven_time = 0;
|
|
new_trade.tp_status = TP_NONE;
|
|
new_trade.tp_strategy = TakeProfitMode;
|
|
new_trade.breakeven_set = false;
|
|
new_trade.entry_atr = GetATRValue();
|
|
new_trade.risk_amount = 0; // Unknown for external trades
|
|
new_trade.entry_reason = "External Trade";
|
|
|
|
int size = ArraySize(managed_trades);
|
|
ArrayResize(managed_trades, size + 1);
|
|
managed_trades[size] = new_trade;
|
|
|
|
if(EnableLogging)
|
|
Print("Added external trade #", ticket, " to management");
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Remove trade from managed array |
|
|
//+------------------------------------------------------------------+
|
|
void RemoveTradeFromArray(int index)
|
|
{
|
|
if(index < 0 || index >= ArraySize(managed_trades)) return;
|
|
|
|
for(int i = index; i < ArraySize(managed_trades) - 1; i++)
|
|
{
|
|
managed_trades[i] = managed_trades[i + 1];
|
|
}
|
|
ArrayResize(managed_trades, ArraySize(managed_trades) - 1);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Execute trading strategies |
|
|
//+------------------------------------------------------------------+
|
|
void ExecuteTradingStrategies()
|
|
{
|
|
// Check for new bar
|
|
static datetime last_check_time = 0;
|
|
datetime current_time = iTime(_Symbol, PERIOD_CURRENT, 0);
|
|
if(current_time == last_check_time) return;
|
|
last_check_time = current_time;
|
|
|
|
// Check if we can open new positions
|
|
if(CountCurrentPositions() >= MaxPositions) return;
|
|
|
|
// Example: Simple MA crossover strategy
|
|
if(MAEntryType == MA_SIMPLE_CROSS)
|
|
{
|
|
double ma_fast_buffer[2], ma_slow_buffer[2];
|
|
|
|
// Copy MA values
|
|
if(CopyBuffer(g_ma_fast_handle, 0, 0, 2, ma_fast_buffer) != 2) return;
|
|
if(CopyBuffer(g_ma_slow_handle, 0, 0, 2, ma_slow_buffer) != 2) return;
|
|
|
|
double ma_fast_current = ma_fast_buffer[0];
|
|
double ma_fast_prev = ma_fast_buffer[1];
|
|
double ma_slow_current = ma_slow_buffer[0];
|
|
double ma_slow_prev = ma_slow_buffer[1];
|
|
|
|
// Check for crossover
|
|
if(ma_fast_prev <= ma_slow_prev && ma_fast_current > ma_slow_current)
|
|
{
|
|
// Bullish crossover - Buy signal
|
|
OpenBuyOrder();
|
|
}
|
|
else if(ma_fast_prev >= ma_slow_prev && ma_fast_current < ma_slow_current)
|
|
{
|
|
// Bearish crossover - Sell signal
|
|
OpenSellOrder();
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Count current positions |
|
|
//+------------------------------------------------------------------+
|
|
int CountCurrentPositions()
|
|
{
|
|
int count = 0;
|
|
for(int i = 0; i < PositionsTotal(); i++)
|
|
{
|
|
if(posInfo.SelectByIndex(i))
|
|
{
|
|
if(posInfo.Symbol() == _Symbol && posInfo.Magic() == TradingMagic)
|
|
count++;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Open buy order with risk management |
|
|
//+------------------------------------------------------------------+
|
|
void OpenBuyOrder()
|
|
{
|
|
double lot_size = CalculateLotSize();
|
|
double stop_loss = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID) - ATR_Multiplier * GetATRValue(), _Digits);
|
|
double take_profit = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID) + ATR_TPMultiplier * GetATRValue(), _Digits);
|
|
|
|
// Send buy order
|
|
if(trade.Buy(lot_size, _Symbol, 0, stop_loss, take_profit, "MA Buy Signal"))
|
|
{
|
|
ulong ticket = trade.ResultOrder(); // Changed from ResultHandle()
|
|
Print("Buy order opened: #", ticket);
|
|
|
|
// Wait a bit for the order to be processed
|
|
Sleep(100);
|
|
|
|
// Find the position by ticket
|
|
if(posInfo.SelectByTicket(ticket))
|
|
{
|
|
// Initialize trade info structure
|
|
TradeInfo new_trade;
|
|
new_trade.ticket = ticket;
|
|
new_trade.open_price = posInfo.PriceOpen();
|
|
new_trade.original_volume = lot_size;
|
|
new_trade.current_volume = lot_size;
|
|
new_trade.current_sl = stop_loss;
|
|
new_trade.current_tp = take_profit;
|
|
new_trade.best_profit = 0;
|
|
new_trade.worst_drawdown = 0;
|
|
new_trade.open_time = TimeCurrent();
|
|
new_trade.breakeven_time = 0;
|
|
new_trade.tp_status = TP_NONE;
|
|
new_trade.tp_strategy = TakeProfitMode;
|
|
new_trade.breakeven_set = false;
|
|
new_trade.entry_atr = GetATRValue();
|
|
new_trade.risk_amount = CalculateRiskAmount(lot_size, new_trade.open_price, stop_loss);
|
|
new_trade.entry_reason = "MA Crossover Buy";
|
|
|
|
// Add to managed trades
|
|
int size = ArraySize(managed_trades);
|
|
ArrayResize(managed_trades, size + 1);
|
|
managed_trades[size] = new_trade;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Print("Error opening buy order: ", GetLastError(), " - ", trade.ResultComment());
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Open sell order with risk management |
|
|
//+------------------------------------------------------------------+
|
|
void OpenSellOrder()
|
|
{
|
|
double lot_size = CalculateLotSize();
|
|
double stop_loss = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK) + ATR_Multiplier * GetATRValue(), _Digits);
|
|
double take_profit = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK) - ATR_TPMultiplier * GetATRValue(), _Digits);
|
|
|
|
// Send sell order
|
|
if(trade.Sell(lot_size, _Symbol, 0, stop_loss, take_profit, "MA Sell Signal"))
|
|
{
|
|
ulong ticket = trade.ResultOrder(); // Changed from ResultHandle()
|
|
Print("Sell order opened: #", ticket);
|
|
|
|
// Wait a bit for the order to be processed
|
|
Sleep(100);
|
|
|
|
// Find the position by ticket
|
|
if(posInfo.SelectByTicket(ticket))
|
|
{
|
|
// Initialize trade info structure
|
|
TradeInfo new_trade;
|
|
new_trade.ticket = ticket;
|
|
new_trade.open_price = posInfo.PriceOpen();
|
|
new_trade.original_volume = lot_size;
|
|
new_trade.current_volume = lot_size;
|
|
new_trade.current_sl = stop_loss;
|
|
new_trade.current_tp = take_profit;
|
|
new_trade.best_profit = 0;
|
|
new_trade.worst_drawdown = 0;
|
|
new_trade.open_time = TimeCurrent();
|
|
new_trade.breakeven_time = 0;
|
|
new_trade.tp_status = TP_NONE;
|
|
new_trade.tp_strategy = TakeProfitMode;
|
|
new_trade.breakeven_set = false;
|
|
new_trade.entry_atr = GetATRValue();
|
|
new_trade.risk_amount = CalculateRiskAmount(lot_size, new_trade.open_price, stop_loss);
|
|
new_trade.entry_reason = "MA Crossover Sell";
|
|
|
|
// Add to managed trades
|
|
int size = ArraySize(managed_trades);
|
|
ArrayResize(managed_trades, size + 1);
|
|
managed_trades[size] = new_trade;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Print("Error opening sell order: ", GetLastError(), " - ", trade.ResultComment());
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Calculate lot size based on risk management |
|
|
//+------------------------------------------------------------------+
|
|
double CalculateLotSize()
|
|
{
|
|
double risk_amount = AccountInfoDouble(ACCOUNT_BALANCE) * RiskPercent / 100;
|
|
double lot_size = risk_amount / (ATR_Multiplier * GetATRValue());
|
|
lot_size = NormalizeDouble(lot_size, 2);
|
|
|
|
// Apply minimum and maximum lot size limits
|
|
if(lot_size < MinLotSize) lot_size = MinLotSize;
|
|
if(lot_size > MaxLotSize) lot_size = MaxLotSize;
|
|
|
|
return lot_size;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Calculate risk amount based on position size |
|
|
//+------------------------------------------------------------------+
|
|
double CalculateRiskAmount(double lot_size, double entry_price, double stop_loss)
|
|
{
|
|
double stop_distance = MathAbs(entry_price - stop_loss);
|
|
double tick_value = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
|
|
double tick_size = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
|
|
|
|
if(tick_size > 0)
|
|
{
|
|
double stop_points = stop_distance / _Point;
|
|
double risk_amount = lot_size * stop_points * tick_value * (_Point / tick_size);
|
|
return risk_amount;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Update risk data for a trade |
|
|
//+------------------------------------------------------------------+
|
|
void UpdateRiskData(TradeInfo &trade_info)
|
|
{
|
|
// Example: Update ATR-based trailing stop
|
|
if(EnableATRSizing)
|
|
{
|
|
double atr_value = GetATRValue();
|
|
double trail_stop = trade_info.open_price + atr_value * ATR_Multiplier;
|
|
|
|
if(trade_info.tp_status == TP_NONE)
|
|
{
|
|
trade_info.current_sl = trail_stop;
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Close a trade by ticket number |
|
|
//+------------------------------------------------------------------+
|
|
void CloseTrade(TradeInfo &trade_info)
|
|
{
|
|
// Find and close the trade
|
|
for(int i = 0; i < ArraySize(managed_trades); i++)
|
|
{
|
|
if(managed_trades[i].ticket == trade_info.ticket)
|
|
{
|
|
// Close the trade
|
|
trade.PositionClose(managed_trades[i].ticket);
|
|
Print("Trade #", managed_trades[i].ticket, " closed");
|
|
|
|
// Remove from managed trades
|
|
for(int j = i; j < ArraySize(managed_trades) - 1; j++)
|
|
{
|
|
managed_trades[j] = managed_trades[j + 1];
|
|
}
|
|
ArrayResize(managed_trades, ArraySize(managed_trades) - 1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Initialize strategy performance data |
|
|
//+------------------------------------------------------------------+
|
|
void InitializeStrategyPerformance()
|
|
{
|
|
for(int i = 0; i < ArraySize(strategy_performance); i++)
|
|
{
|
|
strategy_performance[i].strategy = (ENUM_TP_STRATEGY)i;
|
|
strategy_performance[i].trades_count = 0;
|
|
strategy_performance[i].total_profit = 0;
|
|
strategy_performance[i].total_loss = 0;
|
|
strategy_performance[i].avg_profit = 0;
|
|
strategy_performance[i].avg_win = 0;
|
|
strategy_performance[i].avg_loss = 0;
|
|
strategy_performance[i].max_drawdown = 0;
|
|
strategy_performance[i].win_rate = 0;
|
|
strategy_performance[i].profit_factor = 0;
|
|
strategy_performance[i].expectancy = 0;
|
|
strategy_performance[i].sharpe_ratio = 0;
|
|
strategy_performance[i].recovery_factor = 0;
|
|
strategy_performance[i].score = 0;
|
|
strategy_performance[i].profit_index = 0;
|
|
strategy_performance[i].last_update = 0;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Get entry mode description |
|
|
//+------------------------------------------------------------------+
|
|
string GetEntryModeDescription()
|
|
{
|
|
switch(MAEntryType)
|
|
{
|
|
case MA_SIMPLE_CROSS: return "Simple MA Crossover";
|
|
case MA_TRIPLE_CROSS: return "Triple MA Crossover";
|
|
case MA_PULLBACK: return "MA Pullback";
|
|
case MA_MOMENTUM: return "MA Momentum";
|
|
default: return "Disabled";
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Create performance dashboard |
|
|
//+------------------------------------------------------------------+
|
|
void CreateDashboard()
|
|
{
|
|
// Example: Create a simple dashboard object
|
|
string obj_name = "PerformanceDashboard";
|
|
if(!ObjectCreate(0, obj_name, OBJ_LABEL, 0, 0, 0))
|
|
{
|
|
Print("Error creating dashboard object: ", GetLastError());
|
|
return;
|
|
}
|
|
|
|
ObjectSetInteger(0, obj_name, OBJPROP_XSIZE, 300);
|
|
ObjectSetInteger(0, obj_name, OBJPROP_YSIZE, 200);
|
|
ObjectSetInteger(0, obj_name, OBJPROP_XDISTANCE, 10);
|
|
ObjectSetInteger(0, obj_name, OBJPROP_YDISTANCE, 10);
|
|
ObjectSetInteger(0, obj_name, OBJPROP_FONTSIZE, 10);
|
|
ObjectSetInteger(0, obj_name, OBJPROP_COLOR, clrWhite);
|
|
|
|
// Set initial text
|
|
UpdateDashboard();
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Update performance dashboard |
|
|
//+------------------------------------------------------------------+
|
|
void UpdateDashboard()
|
|
{
|
|
// Example: Update dashboard text with performance data
|
|
string obj_name = "PerformanceDashboard";
|
|
string text = "=== PERFORMANCE DASHBOARD ===\n";
|
|
text += "Account Balance: $" + DoubleToString(account_start_balance, 2) + "\n";
|
|
text += "Equity: $" + DoubleToString(AccountInfoDouble(ACCOUNT_EQUITY), 2) + "\n";
|
|
text += "Floating Profit: $" + DoubleToString(AccountInfoDouble(ACCOUNT_PROFIT), 2) + "\n";
|
|
text += "Total Trades: " + IntegerToString(ArraySize(managed_trades)) + "\n";
|
|
text += "Winning Trades: " + IntegerToString(session_wins) + "\n";
|
|
text += "Losing Trades: " + IntegerToString(session_losses) + "\n";
|
|
text += "Session Profit: $" + DoubleToString(session_profit, 2) + "\n";
|
|
text += "Session Loss: $" + DoubleToString(session_loss, 2) + "\n";
|
|
text += "Max Drawdown: $" + DoubleToString(max_historical_drawdown, 2) + "\n";
|
|
text += "Current DD: $" + DoubleToString(current_drawdown, 2) + "\n";
|
|
|
|
ObjectSetString(0, obj_name, OBJPROP_TEXT, text);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Destroy dashboard object |
|
|
//+------------------------------------------------------------------+
|
|
void DestroyDashboard()
|
|
{
|
|
string obj_name = "PerformanceDashboard";
|
|
ObjectDelete(0, obj_name);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Find largest winning trade |
|
|
//+------------------------------------------------------------------+
|
|
double FindLargestWin()
|
|
{
|
|
double largest = 0;
|
|
for(int i = 0; i < ArraySize(strategy_performance); i++)
|
|
{
|
|
for(int j = 0; j < MathMin(strategy_performance[i].trades_count, 100); j++)
|
|
{
|
|
if(strategy_performance[i].trade_profits[j] > largest)
|
|
largest = strategy_performance[i].trade_profits[j];
|
|
}
|
|
}
|
|
return largest;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Find largest losing trade |
|
|
//+------------------------------------------------------------------+
|
|
double FindLargestLoss()
|
|
{
|
|
double largest = 0;
|
|
for(int i = 0; i < ArraySize(strategy_performance); i++)
|
|
{
|
|
for(int j = 0; j < MathMin(strategy_performance[i].trades_count, 100); j++)
|
|
{
|
|
if(strategy_performance[i].trade_profits[j] < largest)
|
|
largest = strategy_performance[i].trade_profits[j];
|
|
}
|
|
}
|
|
return MathAbs(largest);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Convert boolean to string |
|
|
//+------------------------------------------------------------------+
|
|
string BoolToString(bool value)
|
|
{
|
|
return value ? "Yes" : "No";
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Calculate win rate |
|
|
//+------------------------------------------------------------------+
|
|
double CalculateWinRate()
|
|
{
|
|
if(session_wins + session_losses == 0) return 0;
|
|
return (double)session_wins / (session_wins + session_losses) * 100.0;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Calculate average win |
|
|
//+------------------------------------------------------------------+
|
|
double CalculateAverageWin()
|
|
{
|
|
if(session_wins == 0) return 0;
|
|
return session_profit / session_wins;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Calculate average loss |
|
|
//+------------------------------------------------------------------+
|
|
double CalculateAverageLoss()
|
|
{
|
|
if(session_losses == 0) return 0;
|
|
return MathAbs(session_loss) / session_losses;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Calculate overall profit factor |
|
|
//+------------------------------------------------------------------+
|
|
double CalculateOverallProfitFactor()
|
|
{
|
|
if(session_loss == 0)
|
|
return (session_profit > 0) ? 999.99 : 0;
|
|
return session_profit / MathAbs(session_loss);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| OnTester - Optimization fitness function |
|
|
//+------------------------------------------------------------------+
|
|
double OnTester()
|
|
{
|
|
// Ensure minimum trades for valid optimization
|
|
double total_trades = session_wins + session_losses;
|
|
if(total_trades < 20) return 0;
|
|
double win_rate = CalculateWinRate();
|
|
double profit_factor = CalculateOverallProfitFactor();
|
|
double total_profit = AccountInfoDouble(ACCOUNT_BALANCE) - account_start_balance;
|
|
double roi = (total_profit / account_start_balance) * 100;
|
|
// Risk-adjusted metrics
|
|
double sharpe_ratio = 0;
|
|
if(max_historical_drawdown > 0)
|
|
sharpe_ratio = (roi / max_historical_drawdown);
|
|
double recovery_factor = 0;
|
|
if(max_historical_drawdown > 0)
|
|
recovery_factor = (total_profit / (account_start_balance * max_historical_drawdown / 100));
|
|
// Average profit per trade
|
|
double avg_profit_per_trade = total_profit / total_trades;
|
|
double expectancy = (win_rate / 100 * CalculateAverageWin()) -
|
|
((100 - win_rate) / 100 * CalculateAverageLoss());
|
|
// Build composite score with multiple objectives
|
|
double score = 0;
|
|
// 1. Profitability (30%)
|
|
double profit_score = 0;
|
|
if(roi > 0)
|
|
{
|
|
profit_score += MathMin(roi / 100, 1.0) * 0.15; // ROI component
|
|
profit_score += MathMin(profit_factor / 3, 1.0) * 0.15; // PF component
|
|
}
|
|
// 2. Risk-Adjusted Returns (25%)
|
|
double risk_score = 0;
|
|
if(sharpe_ratio > 0)
|
|
{
|
|
risk_score += MathMin(sharpe_ratio / 2, 1.0) * 0.15;
|
|
risk_score += MathMin(recovery_factor / 3, 1.0) * 0.10;
|
|
}
|
|
// 3. Consistency (25%)
|
|
double consistency_score = 0;
|
|
consistency_score += (win_rate / 100) * 0.15;
|
|
consistency_score += MathMin(total_trades / 100, 1.0) * 0.10;
|
|
// 4. Risk Control (20%)
|
|
double risk_control = 1.0;
|
|
if(max_historical_drawdown > MaxDrawdownPercent)
|
|
risk_control = 0.5; // Heavy penalty for exceeding max drawdown
|
|
else
|
|
risk_control = 1.0 - (max_historical_drawdown / (MaxDrawdownPercent * 2));
|
|
risk_control *= 0.20;
|
|
// Combine all components
|
|
score = profit_score + risk_score + consistency_score + risk_control;
|
|
// Apply additional filters
|
|
if(profit_factor < 1.0) score *= 0.5; // Penalty for losing system
|
|
if(win_rate < 30) score *= 0.7; // Penalty for very low win rate
|
|
if(expectancy < 0) score *= 0.3; // Heavy penalty for negative expectancy
|
|
// Scale to 0-100
|
|
score = MathMin(score * 100, 100);
|
|
score = MathMax(score, 0);
|
|
// Log optimization results
|
|
if(EnableLogging)
|
|
{
|
|
Print("=== OPTIMIZATION SCORE ===");
|
|
Print("Total Score: ", score);
|
|
Print("ROI: ", roi, "% PF: ", profit_factor, " WR: ", win_rate, "%");
|
|
Print("Sharpe: ", sharpe_ratio, " Recovery: ", recovery_factor);
|
|
Print("Max DD: ", max_historical_drawdown, "% Trades: ", total_trades);
|
|
}
|
|
return score;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| END OF ENHANCED RISK MANAGEMENT OVERLAY EA v4.0 |
|
|
//+------------------------------------------------------------------+
|