forked from 188194188/Algo_bot_mt5
1213 lines
43 KiB
MQL5
1213 lines
43 KiB
MQL5
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| DAX_ORB_Ultimate_AI_MT5.mq5 |
|
||
|
|
//| AI-Enhanced ORB Trading Bot |
|
||
|
|
//| Version 2.0 |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
#property copyright "AI Trading Systems"
|
||
|
|
#property link "https://github.com/ai-trading"
|
||
|
|
#property version "2.00"
|
||
|
|
#property description "DAX Opening Range Breakout with AI/ML Integration"
|
||
|
|
#property description "- Advanced AI signal filtering and market regime detection"
|
||
|
|
#property description "- Dynamic risk management and position sizing"
|
||
|
|
#property description "- Real-time volatility adaptation"
|
||
|
|
#property description "- News sentiment integration"
|
||
|
|
|
||
|
|
//--- Input parameters
|
||
|
|
//============================= ORB SETTINGS =============================
|
||
|
|
input group "ORB Settings"
|
||
|
|
input int InpORBStartHour = 7; // ORB Start Hour (UTC)
|
||
|
|
input int InpORBStartMinute = 40; // ORB Start Minute
|
||
|
|
input int InpORBEndHour = 8; // ORB End Hour (UTC)
|
||
|
|
input int InpORBEndMinute = 0; // ORB End Minute
|
||
|
|
input bool InpExcludeWicks = true; // Exclude Wicks from ORB
|
||
|
|
input int InpMarketCloseHour = 16; // Market Close Hour
|
||
|
|
|
||
|
|
//============================= AI/ML SETTINGS =============================
|
||
|
|
input group "AI/ML Settings"
|
||
|
|
input bool InpEnableAI = true; // Enable AI Integration
|
||
|
|
input double InpAIThreshold = 0.7; // AI Confidence Threshold (0.1-1.0)
|
||
|
|
input int InpMarketRegimeWindow = 50; // Market Regime Window (20-200)
|
||
|
|
input int InpFeaturePeriod = 100; // Feature Engineering Period (50-500)
|
||
|
|
input double InpNewsSentimentWeight = 0.3; // News Sentiment Weight (0.0-1.0)
|
||
|
|
|
||
|
|
//============================= RISK MANAGEMENT =============================
|
||
|
|
input group "Risk Management"
|
||
|
|
input double InpVolume = 0.1; // Volume (Lots)
|
||
|
|
input bool InpUseDynamicSizing = true; // Dynamic Position Sizing
|
||
|
|
input double InpRiskPerTrade = 1.0; // Risk Per Trade (%)
|
||
|
|
input bool InpUseDynamicSL = true; // Use Dynamic SL/TP
|
||
|
|
input double InpBaseSL = 30; // Base SL (Pips)
|
||
|
|
input double InpBaseTP = 90; // Base TP (Pips)
|
||
|
|
input double InpVolatilityFactor = 1.5; // Volatility Adjustment Factor
|
||
|
|
input double InpMinRR = 2.0; // Minimum R:R Ratio
|
||
|
|
input string InpMagicComment = "DAX_ORB_AI"; // Order Comment
|
||
|
|
|
||
|
|
//============================= TRAILING STOP =============================
|
||
|
|
input group "Trailing Stop"
|
||
|
|
input bool InpUseTrailing = true; // Use Trailing Stop
|
||
|
|
input double InpTrailStart = 1.0; // Trail Start (ATR multiplier)
|
||
|
|
input double InpTrailDistance = 1.0; // Trail Distance (ATR multiplier)
|
||
|
|
|
||
|
|
//--- Global variables
|
||
|
|
//============================= INDICATORS =============================
|
||
|
|
int atr_handle;
|
||
|
|
int ema9_handle, ema21_handle, ema50_handle;
|
||
|
|
int rsi_handle;
|
||
|
|
int macd_handle;
|
||
|
|
int bb_handle;
|
||
|
|
int stddev_handle;
|
||
|
|
int momentum_handle;
|
||
|
|
|
||
|
|
//============================= ORB VARIABLES =============================
|
||
|
|
double orb_high = 0;
|
||
|
|
double orb_low = 0;
|
||
|
|
bool orb_ready = false;
|
||
|
|
double orb_building_high = 0;
|
||
|
|
double orb_building_low = 0;
|
||
|
|
datetime last_orb_date = 0;
|
||
|
|
double highest_since_entry = 0;
|
||
|
|
double lowest_since_entry = DBL_MAX;
|
||
|
|
|
||
|
|
//============================= AI/ML VARIABLES =============================
|
||
|
|
double price_features[];
|
||
|
|
double volume_features[];
|
||
|
|
double volatility_features[];
|
||
|
|
double recent_predictions[];
|
||
|
|
double current_market_regime = 0; // -1 = bearish, 0 = neutral, 1 = bullish
|
||
|
|
double ai_signal_confidence = 0;
|
||
|
|
double last_news_sentiment = 0;
|
||
|
|
|
||
|
|
//============================= DYNAMIC RISK VARIABLES =============================
|
||
|
|
double current_volatility = 0;
|
||
|
|
double market_stress = 0;
|
||
|
|
double adaptive_risk_multiplier = 1.0;
|
||
|
|
|
||
|
|
//============================= MAGIC NUMBER =============================
|
||
|
|
int magic_number = 20241105;
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Expert initialization function |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
int OnInit()
|
||
|
|
{
|
||
|
|
//--- Initialize indicators
|
||
|
|
atr_handle = iATR(_Symbol, PERIOD_CURRENT, 14);
|
||
|
|
ema9_handle = iMA(_Symbol, PERIOD_CURRENT, 9, 0, MODE_EMA, PRICE_CLOSE);
|
||
|
|
ema21_handle = iMA(_Symbol, PERIOD_CURRENT, 21, 0, MODE_EMA, PRICE_CLOSE);
|
||
|
|
ema50_handle = iMA(_Symbol, PERIOD_CURRENT, 50, 0, MODE_EMA, PRICE_CLOSE);
|
||
|
|
rsi_handle = iRSI(_Symbol, PERIOD_CURRENT, 14, PRICE_CLOSE);
|
||
|
|
macd_handle = iMACD(_Symbol, PERIOD_CURRENT, 12, 26, 9, PRICE_CLOSE);
|
||
|
|
bb_handle = iBands(_Symbol, PERIOD_CURRENT, 20, 0, 2.0, PRICE_CLOSE);
|
||
|
|
stddev_handle = iStdDev(_Symbol, PERIOD_CURRENT, 20, 0, MODE_SMA, PRICE_CLOSE);
|
||
|
|
momentum_handle = iMomentum(_Symbol, PERIOD_CURRENT, 14, PRICE_CLOSE);
|
||
|
|
|
||
|
|
//--- Check indicator handles
|
||
|
|
if(atr_handle == INVALID_HANDLE || ema9_handle == INVALID_HANDLE ||
|
||
|
|
ema21_handle == INVALID_HANDLE || ema50_handle == INVALID_HANDLE ||
|
||
|
|
rsi_handle == INVALID_HANDLE || macd_handle == INVALID_HANDLE ||
|
||
|
|
bb_handle == INVALID_HANDLE || stddev_handle == INVALID_HANDLE ||
|
||
|
|
momentum_handle == INVALID_HANDLE)
|
||
|
|
{
|
||
|
|
Print("Error initializing indicators");
|
||
|
|
return INIT_FAILED;
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Initialize AI components
|
||
|
|
if(InpEnableAI)
|
||
|
|
{
|
||
|
|
InitializeAIFeatures();
|
||
|
|
Print("AI Integration enabled");
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Initialize dynamic risk parameters
|
||
|
|
double atr_buffer[];
|
||
|
|
ArraySetAsSeries(atr_buffer, true);
|
||
|
|
if(CopyBuffer(atr_handle, 0, 0, 1, atr_buffer) > 0)
|
||
|
|
current_volatility = atr_buffer[0];
|
||
|
|
|
||
|
|
adaptive_risk_multiplier = 1.0;
|
||
|
|
|
||
|
|
Print("DAX ORB Ultimate AI MT5 EA started successfully");
|
||
|
|
Print("AI Enabled: ", InpEnableAI, ", Dynamic SL/TP: ", InpUseDynamicSL, ", Dynamic Sizing: ", InpUseDynamicSizing);
|
||
|
|
|
||
|
|
return INIT_SUCCEEDED;
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Expert deinitialization function |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void OnDeinit(const int reason)
|
||
|
|
{
|
||
|
|
//--- Release indicator handles
|
||
|
|
IndicatorRelease(atr_handle);
|
||
|
|
IndicatorRelease(ema9_handle);
|
||
|
|
IndicatorRelease(ema21_handle);
|
||
|
|
IndicatorRelease(ema50_handle);
|
||
|
|
IndicatorRelease(rsi_handle);
|
||
|
|
IndicatorRelease(macd_handle);
|
||
|
|
IndicatorRelease(bb_handle);
|
||
|
|
IndicatorRelease(stddev_handle);
|
||
|
|
IndicatorRelease(momentum_handle);
|
||
|
|
|
||
|
|
Print("DAX ORB Ultimate AI MT5 EA stopped");
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Expert tick function |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void OnTick()
|
||
|
|
{
|
||
|
|
//--- Check for new bar
|
||
|
|
static datetime last_bar_time = 0;
|
||
|
|
datetime current_bar_time = iTime(_Symbol, PERIOD_CURRENT, 0);
|
||
|
|
|
||
|
|
if(current_bar_time == last_bar_time)
|
||
|
|
return;
|
||
|
|
|
||
|
|
last_bar_time = current_bar_time;
|
||
|
|
|
||
|
|
//--- Main logic on new bar
|
||
|
|
OnBar();
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| New bar processing function |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void OnBar()
|
||
|
|
{
|
||
|
|
datetime current_time = TimeCurrent();
|
||
|
|
MqlDateTime dt_struct;
|
||
|
|
TimeToStruct(current_time, dt_struct);
|
||
|
|
datetime current_date = StringToTime(StringFormat("%04d.%02d.%02d", dt_struct.year, dt_struct.mon, dt_struct.day));
|
||
|
|
|
||
|
|
//--- Reset ORB on new day
|
||
|
|
if(current_date != last_orb_date)
|
||
|
|
{
|
||
|
|
last_orb_date = current_date;
|
||
|
|
orb_high = 0;
|
||
|
|
orb_low = 0;
|
||
|
|
orb_ready = false;
|
||
|
|
orb_building_high = 0;
|
||
|
|
orb_building_low = 0;
|
||
|
|
ResetAIFeatures();
|
||
|
|
Print("New day - ORB and AI features reset");
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Update AI features and market analysis
|
||
|
|
if(InpEnableAI && Bars(_Symbol, PERIOD_CURRENT) > InpFeaturePeriod)
|
||
|
|
{
|
||
|
|
UpdateAIFeatures();
|
||
|
|
AnalyzeMarketRegime();
|
||
|
|
UpdateVolatilityMetrics();
|
||
|
|
UpdateNewsSentiment();
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Build ORB during specified period
|
||
|
|
if(IsORBPeriod(current_time) && !orb_ready)
|
||
|
|
{
|
||
|
|
double high_val = InpExcludeWicks ? iClose(_Symbol, PERIOD_CURRENT, 1) : iHigh(_Symbol, PERIOD_CURRENT, 1);
|
||
|
|
double low_val = InpExcludeWicks ? iClose(_Symbol, PERIOD_CURRENT, 1) : iLow(_Symbol, PERIOD_CURRENT, 1);
|
||
|
|
|
||
|
|
if(orb_building_high == 0 || orb_building_low == 0)
|
||
|
|
{
|
||
|
|
orb_building_high = high_val;
|
||
|
|
orb_building_low = low_val;
|
||
|
|
Print("ORB building: High=", orb_building_high, ", Low=", orb_building_low);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
orb_building_high = MathMax(orb_building_high, high_val);
|
||
|
|
orb_building_low = MathMin(orb_building_low, low_val);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Finalize ORB
|
||
|
|
if(ORBEnded(current_time) && !orb_ready && orb_building_high > 0)
|
||
|
|
{
|
||
|
|
orb_high = orb_building_high;
|
||
|
|
orb_low = orb_building_low;
|
||
|
|
orb_ready = true;
|
||
|
|
double orb_range = orb_high - orb_low;
|
||
|
|
Print("ORB finalized: High=", orb_high, ", Low=", orb_low, ", Range=", orb_range / _Point, " points");
|
||
|
|
|
||
|
|
//--- Update AI with ORB completion
|
||
|
|
if(InpEnableAI)
|
||
|
|
{
|
||
|
|
CalculateAISignalConfidence();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Update trailing stops
|
||
|
|
if(PositionsTotal() > 0)
|
||
|
|
{
|
||
|
|
UpdateTrailingStops();
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Look for entry signals
|
||
|
|
if(GetPositionCount() == 0 && orb_ready && IsMarketOpen(current_time))
|
||
|
|
{
|
||
|
|
CheckEntrySignals();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Check if current time is ORB period |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool IsORBPeriod(datetime time)
|
||
|
|
{
|
||
|
|
MqlDateTime dt;
|
||
|
|
TimeToStruct(time, dt);
|
||
|
|
|
||
|
|
int start_minutes = InpORBStartHour * 60 + InpORBStartMinute;
|
||
|
|
int end_minutes = InpORBEndHour * 60 + InpORBEndMinute;
|
||
|
|
int current_minutes = dt.hour * 60 + dt.min;
|
||
|
|
|
||
|
|
return (current_minutes >= start_minutes && current_minutes < end_minutes);
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Check if ORB period has ended |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool ORBEnded(datetime time)
|
||
|
|
{
|
||
|
|
MqlDateTime dt;
|
||
|
|
TimeToStruct(time, dt);
|
||
|
|
|
||
|
|
int end_minutes = InpORBEndHour * 60 + InpORBEndMinute;
|
||
|
|
int current_minutes = dt.hour * 60 + dt.min;
|
||
|
|
|
||
|
|
return (current_minutes == end_minutes);
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Check if market is open |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool IsMarketOpen(datetime time)
|
||
|
|
{
|
||
|
|
MqlDateTime dt;
|
||
|
|
TimeToStruct(time, dt);
|
||
|
|
|
||
|
|
return (dt.hour >= InpORBStartHour && dt.hour <= InpMarketCloseHour);
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Check for entry signals |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CheckEntrySignals()
|
||
|
|
{
|
||
|
|
double close = iClose(_Symbol, PERIOD_CURRENT, 0);
|
||
|
|
double high = iHigh(_Symbol, PERIOD_CURRENT, 0);
|
||
|
|
double low = iLow(_Symbol, PERIOD_CURRENT, 0);
|
||
|
|
|
||
|
|
//--- Check for ORB breakout
|
||
|
|
bool breakout_bull = high > orb_high;
|
||
|
|
bool breakout_bear = low < orb_low;
|
||
|
|
|
||
|
|
if(!breakout_bull && !breakout_bear)
|
||
|
|
return;
|
||
|
|
|
||
|
|
//--- Get current market conditions
|
||
|
|
double atr_buffer[];
|
||
|
|
ArraySetAsSeries(atr_buffer, true);
|
||
|
|
if(CopyBuffer(atr_handle, 0, 0, 1, atr_buffer) <= 0)
|
||
|
|
return;
|
||
|
|
|
||
|
|
double atr_value = atr_buffer[0];
|
||
|
|
current_volatility = atr_value;
|
||
|
|
|
||
|
|
//--- AI Signal Analysis
|
||
|
|
bool ai_approval = true;
|
||
|
|
if(InpEnableAI)
|
||
|
|
{
|
||
|
|
ai_approval = (ai_signal_confidence >= InpAIThreshold);
|
||
|
|
Print("AI Signal Confidence: ", DoubleToString(ai_signal_confidence, 3),
|
||
|
|
", Market Regime: ", DoubleToString(current_market_regime, 2));
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Traditional technical analysis
|
||
|
|
double ema9_buffer[], ema21_buffer[], rsi_buffer[], macd_main[], macd_signal[];
|
||
|
|
ArraySetAsSeries(ema9_buffer, true);
|
||
|
|
ArraySetAsSeries(ema21_buffer, true);
|
||
|
|
ArraySetAsSeries(rsi_buffer, true);
|
||
|
|
ArraySetAsSeries(macd_main, true);
|
||
|
|
ArraySetAsSeries(macd_signal, true);
|
||
|
|
|
||
|
|
if(CopyBuffer(ema9_handle, 0, 0, 1, ema9_buffer) <= 0 ||
|
||
|
|
CopyBuffer(ema21_handle, 0, 0, 1, ema21_buffer) <= 0 ||
|
||
|
|
CopyBuffer(rsi_handle, 0, 0, 1, rsi_buffer) <= 0 ||
|
||
|
|
CopyBuffer(macd_handle, 0, 0, 1, macd_main) <= 0 ||
|
||
|
|
CopyBuffer(macd_handle, 1, 0, 1, macd_signal) <= 0)
|
||
|
|
return;
|
||
|
|
|
||
|
|
double ema9_value = ema9_buffer[0];
|
||
|
|
double ema21_value = ema21_buffer[0];
|
||
|
|
double rsi_value = rsi_buffer[0];
|
||
|
|
double macd_value = macd_main[0];
|
||
|
|
double macd_signal_value = macd_signal[0];
|
||
|
|
|
||
|
|
//--- Technical filter scores
|
||
|
|
int bull_score = 0;
|
||
|
|
int bear_score = 0;
|
||
|
|
|
||
|
|
//--- EMA trend
|
||
|
|
if(ema9_value > ema21_value) bull_score++;
|
||
|
|
else bear_score++;
|
||
|
|
|
||
|
|
//--- RSI momentum
|
||
|
|
if(rsi_value > 45 && rsi_value < 75) bull_score++;
|
||
|
|
if(rsi_value < 55 && rsi_value > 25) bear_score++;
|
||
|
|
|
||
|
|
//--- MACD direction
|
||
|
|
if(macd_value > macd_signal_value) bull_score++;
|
||
|
|
else bear_score++;
|
||
|
|
|
||
|
|
bool tech_ok_bull = (bull_score >= 2);
|
||
|
|
bool tech_ok_bear = (bear_score >= 2);
|
||
|
|
|
||
|
|
//--- Calculate dynamic position size
|
||
|
|
double position_volume = CalculateDynamicPositionSize();
|
||
|
|
|
||
|
|
//--- Execute BULLISH breakout
|
||
|
|
if(breakout_bull && tech_ok_bull && ai_approval)
|
||
|
|
{
|
||
|
|
double entry_price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
||
|
|
|
||
|
|
//--- Calculate dynamic SL/TP
|
||
|
|
double sl, tp;
|
||
|
|
CalculateDynamicSLTP(ORDER_TYPE_BUY, entry_price, atr_value, sl, tp);
|
||
|
|
|
||
|
|
//--- Verify risk/reward ratio
|
||
|
|
double risk_points = (entry_price - sl) / _Point;
|
||
|
|
double reward_points = (tp - entry_price) / _Point;
|
||
|
|
double rr = reward_points / risk_points;
|
||
|
|
|
||
|
|
if(rr >= InpMinRR && risk_points > 0)
|
||
|
|
{
|
||
|
|
if(OrderSend(_Symbol, ORDER_TYPE_BUY, position_volume, entry_price, 10, sl, tp, InpMagicComment, magic_number))
|
||
|
|
{
|
||
|
|
highest_since_entry = entry_price;
|
||
|
|
Print("BUY EXECUTED - Entry: ", entry_price, ", SL: ", sl, " (-", DoubleToString(risk_points, 1), "p), TP: ", tp,
|
||
|
|
" (+", DoubleToString(reward_points, 1), "p), R:R: ", DoubleToString(rr, 2), ", Vol: ", position_volume);
|
||
|
|
Print("AI Confidence: ", DoubleToString(ai_signal_confidence, 3), ", Volatility: ", DoubleToString(current_volatility, 5));
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
Print("BUY ORDER FAILED: ", GetLastError());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
Print("BUY REJECTED - Poor R:R: ", DoubleToString(rr, 2), " (min: ", InpMinRR, "), Risk: ", DoubleToString(risk_points, 1), "p");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//--- Execute BEARISH breakout
|
||
|
|
else if(breakout_bear && tech_ok_bear && ai_approval)
|
||
|
|
{
|
||
|
|
double entry_price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
||
|
|
|
||
|
|
//--- Calculate dynamic SL/TP
|
||
|
|
double sl, tp;
|
||
|
|
CalculateDynamicSLTP(ORDER_TYPE_SELL, entry_price, atr_value, sl, tp);
|
||
|
|
|
||
|
|
//--- Verify risk/reward ratio
|
||
|
|
double risk_points = (sl - entry_price) / _Point;
|
||
|
|
double reward_points = (entry_price - tp) / _Point;
|
||
|
|
double rr = reward_points / risk_points;
|
||
|
|
|
||
|
|
if(rr >= InpMinRR && risk_points > 0)
|
||
|
|
{
|
||
|
|
if(OrderSend(_Symbol, ORDER_TYPE_SELL, position_volume, entry_price, 10, sl, tp, InpMagicComment, magic_number))
|
||
|
|
{
|
||
|
|
lowest_since_entry = entry_price;
|
||
|
|
Print("SELL EXECUTED - Entry: ", entry_price, ", SL: ", sl, " (+", DoubleToString(risk_points, 1), "p), TP: ", tp,
|
||
|
|
" (-", DoubleToString(reward_points, 1), "p), R:R: ", DoubleToString(rr, 2), ", Vol: ", position_volume);
|
||
|
|
Print("AI Confidence: ", DoubleToString(ai_signal_confidence, 3), ", Volatility: ", DoubleToString(current_volatility, 5));
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
Print("SELL ORDER FAILED: ", GetLastError());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
Print("SELL REJECTED - Poor R:R: ", DoubleToString(rr, 2), " (min: ", InpMinRR, "), Risk: ", DoubleToString(risk_points, 1), "p");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if(!ai_approval)
|
||
|
|
Print("TRADE REJECTED - AI Confidence too low: ", DoubleToString(ai_signal_confidence, 3), " < ", InpAIThreshold);
|
||
|
|
if(!tech_ok_bull && !tech_ok_bear)
|
||
|
|
Print("TRADE REJECTED - Technical filter failed. Bull: ", bull_score, "/3, Bear: ", bear_score, "/3");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Update trailing stops |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void UpdateTrailingStops()
|
||
|
|
{
|
||
|
|
if(!InpUseTrailing) return;
|
||
|
|
|
||
|
|
double atr_buffer[];
|
||
|
|
ArraySetAsSeries(atr_buffer, true);
|
||
|
|
if(CopyBuffer(atr_handle, 0, 0, 1, atr_buffer) <= 0)
|
||
|
|
return;
|
||
|
|
|
||
|
|
double atr_value = atr_buffer[0];
|
||
|
|
|
||
|
|
for(int i = 0; i < PositionsTotal(); i++)
|
||
|
|
{
|
||
|
|
if(!PositionSelectByTicket(PositionGetTicket(i))) continue;
|
||
|
|
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
|
||
|
|
if(PositionGetString(POSITION_COMMENT) != InpMagicComment) continue;
|
||
|
|
|
||
|
|
ENUM_POSITION_TYPE pos_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||
|
|
double pos_entry = PositionGetDouble(POSITION_PRICE_OPEN);
|
||
|
|
double pos_sl = PositionGetDouble(POSITION_SL);
|
||
|
|
ulong pos_ticket = PositionGetInteger(POSITION_TICKET);
|
||
|
|
|
||
|
|
if(pos_type == POSITION_TYPE_BUY)
|
||
|
|
{
|
||
|
|
double current_price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
||
|
|
highest_since_entry = MathMax(highest_since_entry, current_price);
|
||
|
|
|
||
|
|
double profit_atr = (highest_since_entry - pos_entry) / atr_value;
|
||
|
|
|
||
|
|
if(profit_atr >= InpTrailStart)
|
||
|
|
{
|
||
|
|
double new_sl = highest_since_entry - atr_value * InpTrailDistance;
|
||
|
|
if(new_sl > pos_sl)
|
||
|
|
{
|
||
|
|
if(!PositionModify(pos_ticket, new_sl, PositionGetDouble(POSITION_TP)))
|
||
|
|
{
|
||
|
|
Print("Failed to modify BUY position: ", GetLastError());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else if(pos_type == POSITION_TYPE_SELL)
|
||
|
|
{
|
||
|
|
double current_price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
||
|
|
lowest_since_entry = MathMin(lowest_since_entry, current_price);
|
||
|
|
|
||
|
|
double profit_atr = (pos_entry - lowest_since_entry) / atr_value;
|
||
|
|
|
||
|
|
if(profit_atr >= InpTrailStart)
|
||
|
|
{
|
||
|
|
double new_sl = lowest_since_entry + atr_value * InpTrailDistance;
|
||
|
|
if(new_sl < pos_sl || pos_sl == 0)
|
||
|
|
{
|
||
|
|
if(!PositionModify(pos_ticket, new_sl, PositionGetDouble(POSITION_TP)))
|
||
|
|
{
|
||
|
|
Print("Failed to modify SELL position: ", GetLastError());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Calculate Simple Moving Average |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
double CalculateSMA(int period)
|
||
|
|
{
|
||
|
|
double sum = 0;
|
||
|
|
for(int i = 0; i < period; i++)
|
||
|
|
{
|
||
|
|
sum += iClose(_Symbol, PERIOD_CURRENT, i);
|
||
|
|
}
|
||
|
|
return sum / period;
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Calculate Standard Deviation |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
double CalculateStdDev(int period)
|
||
|
|
{
|
||
|
|
double mean = CalculateSMA(period);
|
||
|
|
double sum_sq = 0;
|
||
|
|
for(int i = 0; i < period; i++)
|
||
|
|
{
|
||
|
|
double diff = iClose(_Symbol, PERIOD_CURRENT, i) - mean;
|
||
|
|
sum_sq += diff * diff;
|
||
|
|
}
|
||
|
|
return MathSqrt(sum_sq / period);
|
||
|
|
}
|
||
|
|
|
||
|
|
//============================= AI/ML METHODS =============================
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Initialize AI Features |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void InitializeAIFeatures()
|
||
|
|
{
|
||
|
|
ArrayResize(price_features, 0);
|
||
|
|
ArrayResize(volume_features, 0);
|
||
|
|
ArrayResize(volatility_features, 0);
|
||
|
|
ArrayResize(recent_predictions, 0);
|
||
|
|
ai_signal_confidence = 0.5; // neutral starting point
|
||
|
|
current_market_regime = 0;
|
||
|
|
last_news_sentiment = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Reset AI Features |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void ResetAIFeatures()
|
||
|
|
{
|
||
|
|
if(ArraySize(price_features) > InpFeaturePeriod)
|
||
|
|
ArrayResize(price_features, InpFeaturePeriod);
|
||
|
|
if(ArraySize(volume_features) > InpFeaturePeriod)
|
||
|
|
ArrayResize(volume_features, InpFeaturePeriod);
|
||
|
|
if(ArraySize(volatility_features) > InpFeaturePeriod)
|
||
|
|
ArrayResize(volatility_features, InpFeaturePeriod);
|
||
|
|
|
||
|
|
ai_signal_confidence = 0.5;
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Update AI Features |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void UpdateAIFeatures()
|
||
|
|
{
|
||
|
|
double close = iClose(_Symbol, PERIOD_CURRENT, 0);
|
||
|
|
double volume = (double)iVolume(_Symbol, PERIOD_CURRENT, 0);
|
||
|
|
|
||
|
|
double atr_buffer[];
|
||
|
|
ArraySetAsSeries(atr_buffer, true);
|
||
|
|
if(CopyBuffer(atr_handle, 0, 0, 1, atr_buffer) <= 0)
|
||
|
|
return;
|
||
|
|
|
||
|
|
double atr_value = atr_buffer[0];
|
||
|
|
|
||
|
|
//--- Price-based features
|
||
|
|
double price_change = 0;
|
||
|
|
if(Bars(_Symbol, PERIOD_CURRENT) > 1)
|
||
|
|
{
|
||
|
|
double prev_close = iClose(_Symbol, PERIOD_CURRENT, 1);
|
||
|
|
if(prev_close != 0)
|
||
|
|
price_change = (close - prev_close) / prev_close;
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Add to feature arrays
|
||
|
|
int size = ArraySize(price_features);
|
||
|
|
ArrayResize(price_features, size + 1);
|
||
|
|
ArrayResize(volume_features, size + 1);
|
||
|
|
ArrayResize(volatility_features, size + 1);
|
||
|
|
|
||
|
|
price_features[size] = price_change;
|
||
|
|
volume_features[size] = volume;
|
||
|
|
volatility_features[size] = atr_value;
|
||
|
|
|
||
|
|
//--- Maintain feature window size
|
||
|
|
if(ArraySize(price_features) > InpFeaturePeriod)
|
||
|
|
{
|
||
|
|
ArrayRemove(price_features, 0, 1);
|
||
|
|
ArrayRemove(volume_features, 0, 1);
|
||
|
|
ArrayRemove(volatility_features, 0, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Calculate additional ML features
|
||
|
|
CalculateAdvancedFeatures();
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Calculate Advanced Features |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CalculateAdvancedFeatures()
|
||
|
|
{
|
||
|
|
if(ArraySize(price_features) < 20) return;
|
||
|
|
|
||
|
|
//--- Fractal dimension calculation
|
||
|
|
double fractal_dim = CalculateFractalDimension();
|
||
|
|
|
||
|
|
//--- Hurst exponent for mean reversion/trending
|
||
|
|
double hurst_exponent = CalculateHurstExponent();
|
||
|
|
|
||
|
|
//--- Volume-price trend correlation
|
||
|
|
double vp_correlation = CalculateVolumePriceCorrelation();
|
||
|
|
|
||
|
|
//--- Store these for AI decision making
|
||
|
|
Print("ML Features - Fractal: ", DoubleToString(fractal_dim, 3),
|
||
|
|
", Hurst: ", DoubleToString(hurst_exponent, 3),
|
||
|
|
", VP-Corr: ", DoubleToString(vp_correlation, 3));
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Calculate Fractal Dimension |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
double CalculateFractalDimension()
|
||
|
|
{
|
||
|
|
if(ArraySize(price_features) < 10) return 1.5;
|
||
|
|
|
||
|
|
int start_idx = MathMax(0, ArraySize(price_features) - 20);
|
||
|
|
int count = ArraySize(price_features) - start_idx;
|
||
|
|
|
||
|
|
double max_val = price_features[start_idx];
|
||
|
|
double min_val = price_features[start_idx];
|
||
|
|
|
||
|
|
for(int i = start_idx; i < ArraySize(price_features); i++)
|
||
|
|
{
|
||
|
|
max_val = MathMax(max_val, price_features[i]);
|
||
|
|
min_val = MathMin(min_val, price_features[i]);
|
||
|
|
}
|
||
|
|
|
||
|
|
double range = max_val - min_val;
|
||
|
|
if(range == 0) return 1.5;
|
||
|
|
|
||
|
|
//--- Simple approximation of fractal dimension
|
||
|
|
double volatility = CalculateStdDev(20);
|
||
|
|
double fractal_dim = 1.0 + (volatility / range) * 0.5;
|
||
|
|
return MathMax(1.0, MathMin(2.0, fractal_dim));
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Calculate Hurst Exponent |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
double CalculateHurstExponent()
|
||
|
|
{
|
||
|
|
if(ArraySize(price_features) < 20) return 0.5;
|
||
|
|
|
||
|
|
int start_idx = MathMax(0, ArraySize(price_features) - 20);
|
||
|
|
int count = ArraySize(price_features) - start_idx;
|
||
|
|
|
||
|
|
//--- Calculate mean
|
||
|
|
double sum = 0;
|
||
|
|
for(int i = start_idx; i < ArraySize(price_features); i++)
|
||
|
|
sum += price_features[i];
|
||
|
|
double mean = sum / count;
|
||
|
|
|
||
|
|
//--- Calculate variance
|
||
|
|
double sum_sq = 0;
|
||
|
|
for(int i = start_idx; i < ArraySize(price_features); i++)
|
||
|
|
{
|
||
|
|
double diff = price_features[i] - mean;
|
||
|
|
sum_sq += diff * diff;
|
||
|
|
}
|
||
|
|
double variance = sum_sq / count;
|
||
|
|
|
||
|
|
if(variance == 0) return 0.5;
|
||
|
|
|
||
|
|
//--- R/S analysis approximation
|
||
|
|
double cum_deviations[];
|
||
|
|
ArrayResize(cum_deviations, count);
|
||
|
|
|
||
|
|
cum_deviations[0] = price_features[start_idx] - mean;
|
||
|
|
for(int i = 1; i < count; i++)
|
||
|
|
{
|
||
|
|
cum_deviations[i] = cum_deviations[i-1] + (price_features[start_idx + i] - mean);
|
||
|
|
}
|
||
|
|
|
||
|
|
double max_dev = cum_deviations[0];
|
||
|
|
double min_dev = cum_deviations[0];
|
||
|
|
for(int i = 0; i < count; i++)
|
||
|
|
{
|
||
|
|
max_dev = MathMax(max_dev, cum_deviations[i]);
|
||
|
|
min_dev = MathMin(min_dev, cum_deviations[i]);
|
||
|
|
}
|
||
|
|
|
||
|
|
double range = max_dev - min_dev;
|
||
|
|
double standard_dev = MathSqrt(variance);
|
||
|
|
|
||
|
|
if(standard_dev == 0) return 0.5;
|
||
|
|
|
||
|
|
double rs = range / standard_dev;
|
||
|
|
double hurst = MathLog(rs) / MathLog(count);
|
||
|
|
|
||
|
|
return MathMax(0.1, MathMin(0.9, hurst));
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Calculate Volume Price Correlation |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
double CalculateVolumePriceCorrelation()
|
||
|
|
{
|
||
|
|
if(ArraySize(price_features) < 10 || ArraySize(volume_features) < 10) return 0;
|
||
|
|
|
||
|
|
int start_idx = MathMax(0, ArraySize(price_features) - 10);
|
||
|
|
int count = ArraySize(price_features) - start_idx;
|
||
|
|
|
||
|
|
//--- Calculate means
|
||
|
|
double price_sum = 0, volume_sum = 0;
|
||
|
|
for(int i = start_idx; i < ArraySize(price_features); i++)
|
||
|
|
{
|
||
|
|
price_sum += price_features[i];
|
||
|
|
volume_sum += volume_features[i];
|
||
|
|
}
|
||
|
|
double price_mean = price_sum / count;
|
||
|
|
double volume_mean = volume_sum / count;
|
||
|
|
|
||
|
|
//--- Calculate correlation
|
||
|
|
double numerator = 0;
|
||
|
|
double price_var = 0;
|
||
|
|
double volume_var = 0;
|
||
|
|
|
||
|
|
for(int i = start_idx; i < ArraySize(price_features); i++)
|
||
|
|
{
|
||
|
|
double price_diff = price_features[i] - price_mean;
|
||
|
|
double volume_diff = volume_features[i] - volume_mean;
|
||
|
|
numerator += price_diff * volume_diff;
|
||
|
|
price_var += price_diff * price_diff;
|
||
|
|
volume_var += volume_diff * volume_diff;
|
||
|
|
}
|
||
|
|
|
||
|
|
double denominator = MathSqrt(price_var * volume_var);
|
||
|
|
return (denominator == 0) ? 0 : numerator / denominator;
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Analyze Market Regime |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void AnalyzeMarketRegime()
|
||
|
|
{
|
||
|
|
if(ArraySize(price_features) < InpMarketRegimeWindow) return;
|
||
|
|
|
||
|
|
//--- Market regime classification using multiple indicators
|
||
|
|
int start_idx = MathMax(0, ArraySize(price_features) - InpMarketRegimeWindow);
|
||
|
|
|
||
|
|
//--- Trend strength
|
||
|
|
double trend_strength = CalculateTrendStrength(start_idx);
|
||
|
|
|
||
|
|
//--- Volatility regime
|
||
|
|
double vol_regime = CalculateVolatilityRegime(start_idx);
|
||
|
|
|
||
|
|
//--- Momentum regime
|
||
|
|
double momentum_regime = CalculateMomentumRegime();
|
||
|
|
|
||
|
|
//--- Combine signals for overall market regime
|
||
|
|
current_market_regime = (trend_strength + vol_regime + momentum_regime) / 3.0;
|
||
|
|
|
||
|
|
//--- Clamp to [-1, 1] range
|
||
|
|
current_market_regime = MathMax(-1.0, MathMin(1.0, current_market_regime));
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Calculate Trend Strength |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
double CalculateTrendStrength(int start_idx)
|
||
|
|
{
|
||
|
|
int count = ArraySize(price_features) - start_idx;
|
||
|
|
if(count < 5) return 0;
|
||
|
|
|
||
|
|
//--- Linear regression slope
|
||
|
|
double sum_x = 0, sum_y = 0, sum_xy = 0, sum_x2 = 0;
|
||
|
|
|
||
|
|
for(int i = 0; i < count; i++)
|
||
|
|
{
|
||
|
|
double x = i;
|
||
|
|
double y = price_features[start_idx + i];
|
||
|
|
sum_x += x;
|
||
|
|
sum_y += y;
|
||
|
|
sum_xy += x * y;
|
||
|
|
sum_x2 += x * x;
|
||
|
|
}
|
||
|
|
|
||
|
|
double slope = (count * sum_xy - sum_x * sum_y) / (count * sum_x2 - sum_x * sum_x);
|
||
|
|
|
||
|
|
//--- Normalize slope to [-1, 1] range
|
||
|
|
double avg_price = sum_y / count;
|
||
|
|
double normalized_slope = slope / avg_price * 1000; // Scale for readability
|
||
|
|
|
||
|
|
return MathMax(-1.0, MathMin(1.0, normalized_slope));
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Calculate Volatility Regime |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
double CalculateVolatilityRegime(int start_idx)
|
||
|
|
{
|
||
|
|
int count = ArraySize(volatility_features) - start_idx;
|
||
|
|
if(count < 5) return 0;
|
||
|
|
|
||
|
|
//--- Calculate average volatility
|
||
|
|
double sum = 0;
|
||
|
|
for(int i = start_idx; i < ArraySize(volatility_features); i++)
|
||
|
|
sum += volatility_features[i];
|
||
|
|
double avg_vol = sum / count;
|
||
|
|
|
||
|
|
//--- Calculate recent volatility (last 5)
|
||
|
|
double recent_sum = 0;
|
||
|
|
int recent_count = MathMin(5, count);
|
||
|
|
for(int i = ArraySize(volatility_features) - recent_count; i < ArraySize(volatility_features); i++)
|
||
|
|
recent_sum += volatility_features[i];
|
||
|
|
double recent_vol = recent_sum / recent_count;
|
||
|
|
|
||
|
|
//--- High volatility = bearish regime, low volatility = bullish regime
|
||
|
|
double vol_ratio = (avg_vol != 0) ? (avg_vol - recent_vol) / avg_vol : 0;
|
||
|
|
return MathMax(-1.0, MathMin(1.0, vol_ratio));
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Calculate Momentum Regime |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
double CalculateMomentumRegime()
|
||
|
|
{
|
||
|
|
if(Bars(_Symbol, PERIOD_CURRENT) < 20) return 0;
|
||
|
|
|
||
|
|
double rsi_buffer[], macd_hist[];
|
||
|
|
ArraySetAsSeries(rsi_buffer, true);
|
||
|
|
ArraySetAsSeries(macd_hist, true);
|
||
|
|
|
||
|
|
if(CopyBuffer(rsi_handle, 0, 0, 1, rsi_buffer) <= 0 ||
|
||
|
|
CopyBuffer(macd_handle, 2, 0, 10, macd_hist) <= 0)
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
double rsi_value = rsi_buffer[0];
|
||
|
|
|
||
|
|
//--- RSI momentum (50 = neutral)
|
||
|
|
double rsi_momentum = (rsi_value - 50) / 50;
|
||
|
|
|
||
|
|
//--- MACD momentum
|
||
|
|
double avg_macd_hist = 0;
|
||
|
|
int macd_count = MathMin(10, ArraySize(macd_hist));
|
||
|
|
for(int i = 0; i < macd_count; i++)
|
||
|
|
avg_macd_hist += macd_hist[i];
|
||
|
|
avg_macd_hist /= macd_count;
|
||
|
|
|
||
|
|
double macd_momentum = (avg_macd_hist > 0) ? 0.5 : -0.5;
|
||
|
|
|
||
|
|
return (rsi_momentum + macd_momentum) / 2.0;
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Update Volatility Metrics |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void UpdateVolatilityMetrics()
|
||
|
|
{
|
||
|
|
double atr_buffer[], stddev_buffer[];
|
||
|
|
ArraySetAsSeries(atr_buffer, true);
|
||
|
|
ArraySetAsSeries(stddev_buffer, true);
|
||
|
|
|
||
|
|
if(CopyBuffer(atr_handle, 0, 0, 1, atr_buffer) <= 0 ||
|
||
|
|
CopyBuffer(stddev_handle, 0, 0, 1, stddev_buffer) <= 0)
|
||
|
|
return;
|
||
|
|
|
||
|
|
current_volatility = atr_buffer[0];
|
||
|
|
double stddev_value = stddev_buffer[0];
|
||
|
|
|
||
|
|
//--- Market stress indicator
|
||
|
|
double close = iClose(_Symbol, PERIOD_CURRENT, 0);
|
||
|
|
double price_vol = (close != 0) ? stddev_value / close : 0;
|
||
|
|
|
||
|
|
double vol_vol = 0;
|
||
|
|
if(ArraySize(volatility_features) > 10)
|
||
|
|
{
|
||
|
|
// Calculate standard deviation of volatility
|
||
|
|
int start_idx = ArraySize(volatility_features) - 10;
|
||
|
|
double sum = 0;
|
||
|
|
for(int i = start_idx; i < ArraySize(volatility_features); i++)
|
||
|
|
sum += volatility_features[i];
|
||
|
|
double mean_vol = sum / 10;
|
||
|
|
|
||
|
|
double sum_sq = 0;
|
||
|
|
for(int i = start_idx; i < ArraySize(volatility_features); i++)
|
||
|
|
{
|
||
|
|
double diff = volatility_features[i] - mean_vol;
|
||
|
|
sum_sq += diff * diff;
|
||
|
|
}
|
||
|
|
vol_vol = MathSqrt(sum_sq / 10);
|
||
|
|
}
|
||
|
|
|
||
|
|
market_stress = (price_vol + vol_vol) * 100; // Scale to percentage
|
||
|
|
|
||
|
|
//--- Adaptive risk multiplier based on market conditions
|
||
|
|
if(market_stress > 2.0) // High stress
|
||
|
|
adaptive_risk_multiplier = 1.5;
|
||
|
|
else if(market_stress > 1.0) // Medium stress
|
||
|
|
adaptive_risk_multiplier = 1.2;
|
||
|
|
else // Low stress
|
||
|
|
adaptive_risk_multiplier = 0.8;
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Calculate AI Signal Confidence |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CalculateAISignalConfidence()
|
||
|
|
{
|
||
|
|
if(!InpEnableAI || ArraySize(price_features) < 20)
|
||
|
|
{
|
||
|
|
ai_signal_confidence = 0.5;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Multi-factor confidence scoring
|
||
|
|
double confidence_score = 0.5; // Start neutral
|
||
|
|
|
||
|
|
//--- 1. Market regime confidence
|
||
|
|
double regime_confidence = MathAbs(current_market_regime);
|
||
|
|
confidence_score += regime_confidence * 0.3;
|
||
|
|
|
||
|
|
//--- 2. Technical confluence
|
||
|
|
double ema9_buffer[], ema21_buffer[], rsi_buffer[], macd_main[], macd_signal[];
|
||
|
|
ArraySetAsSeries(ema9_buffer, true);
|
||
|
|
ArraySetAsSeries(ema21_buffer, true);
|
||
|
|
ArraySetAsSeries(rsi_buffer, true);
|
||
|
|
ArraySetAsSeries(macd_main, true);
|
||
|
|
ArraySetAsSeries(macd_signal, true);
|
||
|
|
|
||
|
|
if(CopyBuffer(ema9_handle, 0, 0, 1, ema9_buffer) > 0 &&
|
||
|
|
CopyBuffer(ema21_handle, 0, 0, 1, ema21_buffer) > 0 &&
|
||
|
|
CopyBuffer(rsi_handle, 0, 0, 1, rsi_buffer) > 0 &&
|
||
|
|
CopyBuffer(macd_handle, 0, 0, 1, macd_main) > 0 &&
|
||
|
|
CopyBuffer(macd_handle, 1, 0, 1, macd_signal) > 0)
|
||
|
|
{
|
||
|
|
double ema9_value = ema9_buffer[0];
|
||
|
|
double ema21_value = ema21_buffer[0];
|
||
|
|
double rsi_value = rsi_buffer[0];
|
||
|
|
double macd_value = macd_main[0];
|
||
|
|
double macd_signal_value = macd_signal[0];
|
||
|
|
|
||
|
|
int technical_alignment = 0;
|
||
|
|
if((ema9_value > ema21_value && rsi_value > 50 && macd_value > macd_signal_value) ||
|
||
|
|
(ema9_value < ema21_value && rsi_value < 50 && macd_value < macd_signal_value))
|
||
|
|
technical_alignment = 1;
|
||
|
|
|
||
|
|
confidence_score += technical_alignment * 0.2;
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- 3. Volatility environment assessment
|
||
|
|
double vol_confidence = (current_volatility > 0) ? MathMin(1.0, 1.0 / (1.0 + market_stress)) : 0.5;
|
||
|
|
confidence_score += vol_confidence * 0.2;
|
||
|
|
|
||
|
|
//--- 4. ORB quality assessment
|
||
|
|
double orb_range = orb_high - orb_low;
|
||
|
|
double orb_quality = (orb_range > 0) ? MathMin(1.0, orb_range / (current_volatility * 2)) : 0.5;
|
||
|
|
confidence_score += orb_quality * 0.3;
|
||
|
|
|
||
|
|
//--- Normalize to [0, 1] range
|
||
|
|
ai_signal_confidence = MathMax(0.1, MathMin(1.0, confidence_score));
|
||
|
|
|
||
|
|
//--- Add news sentiment if available
|
||
|
|
if(MathAbs(last_news_sentiment) > 0.1)
|
||
|
|
{
|
||
|
|
ai_signal_confidence = ai_signal_confidence * (1.0 - InpNewsSentimentWeight) +
|
||
|
|
MathAbs(last_news_sentiment) * InpNewsSentimentWeight;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//============================= DYNAMIC RISK MANAGEMENT =============================
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Calculate Dynamic Position Size |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
double CalculateDynamicPositionSize()
|
||
|
|
{
|
||
|
|
if(!InpUseDynamicSizing)
|
||
|
|
return InpVolume;
|
||
|
|
|
||
|
|
//--- Account equity based sizing
|
||
|
|
double account_equity = AccountInfoDouble(ACCOUNT_EQUITY);
|
||
|
|
double risk_amount = account_equity * (InpRiskPerTrade / 100.0);
|
||
|
|
|
||
|
|
//--- Calculate risk per pip based on current volatility
|
||
|
|
double risk_pips = InpUseDynamicSL ?
|
||
|
|
(InpBaseSL + current_volatility * InpVolatilityFactor / _Point) :
|
||
|
|
InpBaseSL;
|
||
|
|
|
||
|
|
if(risk_pips <= 0) return InpVolume;
|
||
|
|
|
||
|
|
//--- Position size = Risk amount / (Risk pips * Pip value)
|
||
|
|
double pip_value = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
|
||
|
|
double position_size = risk_amount / (risk_pips * pip_value);
|
||
|
|
|
||
|
|
//--- Apply adaptive risk multiplier
|
||
|
|
position_size *= adaptive_risk_multiplier;
|
||
|
|
|
||
|
|
//--- Convert to lots and apply limits
|
||
|
|
double min_lot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
|
||
|
|
double max_lot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
|
||
|
|
double lot_step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
|
||
|
|
|
||
|
|
position_size = MathMax(min_lot, position_size);
|
||
|
|
position_size = MathMin(InpVolume * 5, position_size); // Max 5x base volume
|
||
|
|
position_size = MathMin(max_lot, position_size);
|
||
|
|
|
||
|
|
//--- Round to lot step
|
||
|
|
position_size = MathFloor(position_size / lot_step) * lot_step;
|
||
|
|
|
||
|
|
return position_size;
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Calculate Dynamic SL/TP |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CalculateDynamicSLTP(ENUM_ORDER_TYPE order_type, double entry_price, double atr_value, double &sl, double &tp)
|
||
|
|
{
|
||
|
|
if(InpUseDynamicSL)
|
||
|
|
{
|
||
|
|
//--- Dynamic SL/TP based on volatility and market conditions
|
||
|
|
double sl_distance = (InpBaseSL + atr_value * InpVolatilityFactor * adaptive_risk_multiplier) * _Point;
|
||
|
|
double tp_distance = sl_distance * InpMinRR; // Maintain minimum R:R
|
||
|
|
|
||
|
|
//--- Adjust for market regime
|
||
|
|
if(MathAbs(current_market_regime) > 0.5)
|
||
|
|
{
|
||
|
|
//--- Strong trending market - wider stops
|
||
|
|
sl_distance *= 1.2;
|
||
|
|
tp_distance *= 1.1;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
//--- Ranging market - tighter stops
|
||
|
|
sl_distance *= 0.9;
|
||
|
|
tp_distance *= 1.0;
|
||
|
|
}
|
||
|
|
|
||
|
|
if(order_type == ORDER_TYPE_BUY)
|
||
|
|
{
|
||
|
|
sl = entry_price - sl_distance;
|
||
|
|
tp = entry_price + tp_distance;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
sl = entry_price + sl_distance;
|
||
|
|
tp = entry_price - tp_distance;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
//--- Fixed SL/TP
|
||
|
|
double sl_pips = InpBaseSL * _Point;
|
||
|
|
double tp_pips = InpBaseTP * _Point;
|
||
|
|
|
||
|
|
if(order_type == ORDER_TYPE_BUY)
|
||
|
|
{
|
||
|
|
sl = entry_price - sl_pips;
|
||
|
|
tp = entry_price + tp_pips;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
sl = entry_price + sl_pips;
|
||
|
|
tp = entry_price - tp_pips;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//============================= NEWS SENTIMENT INTEGRATION =============================
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Update News Sentiment |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void UpdateNewsSentiment()
|
||
|
|
{
|
||
|
|
//--- Update sentiment periodically (not every bar to avoid overprocessing)
|
||
|
|
MqlDateTime dt;
|
||
|
|
TimeToStruct(TimeCurrent(), dt);
|
||
|
|
|
||
|
|
if(dt.min % 15 == 0) // Every 15 minutes
|
||
|
|
{
|
||
|
|
GetNewsSentiment();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Get News Sentiment |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void GetNewsSentiment()
|
||
|
|
{
|
||
|
|
//--- Simplified news sentiment analysis
|
||
|
|
//--- In production, you would integrate with news APIs like:
|
||
|
|
//--- - Alpha Vantage News API
|
||
|
|
//--- - NewsAPI
|
||
|
|
//--- - Financial Modeling Prep
|
||
|
|
//--- - Custom sentiment analysis service
|
||
|
|
|
||
|
|
//--- For now, return simulated sentiment based on market conditions
|
||
|
|
MqlDateTime dt;
|
||
|
|
TimeToStruct(TimeCurrent(), dt);
|
||
|
|
|
||
|
|
double time_score = (dt.hour >= 8 && dt.hour <= 16) ? 0.1 : -0.1; // Market hours boost
|
||
|
|
|
||
|
|
//--- Use volatility as proxy for market stress/sentiment
|
||
|
|
double vol_sentiment = (current_volatility > 0) ?
|
||
|
|
MathMin(0.5, MathMax(-0.5, -market_stress * 0.1)) : 0;
|
||
|
|
|
||
|
|
double simulated_sentiment = time_score + vol_sentiment;
|
||
|
|
last_news_sentiment = MathMax(-1.0, MathMin(1.0, simulated_sentiment));
|
||
|
|
|
||
|
|
if(MathAbs(last_news_sentiment) > 0.1)
|
||
|
|
Print("News Sentiment: ", DoubleToString(last_news_sentiment, 3), " (simulated)");
|
||
|
|
}
|
||
|
|
|
||
|
|
//============================= HELPER FUNCTIONS =============================
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Get position count for this EA |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
int GetPositionCount()
|
||
|
|
{
|
||
|
|
int count = 0;
|
||
|
|
for(int i = 0; i < PositionsTotal(); i++)
|
||
|
|
{
|
||
|
|
if(!PositionSelectByTicket(PositionGetTicket(i))) continue;
|
||
|
|
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
|
||
|
|
if(PositionGetString(POSITION_COMMENT) != InpMagicComment) continue;
|
||
|
|
count++;
|
||
|
|
}
|
||
|
|
return count;
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Order Send function with error handling |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool OrderSend(string symbol, ENUM_ORDER_TYPE order_type, double volume, double price,
|
||
|
|
int slippage, double sl, double tp, string comment, int magic)
|
||
|
|
{
|
||
|
|
MqlTradeRequest request = {};
|
||
|
|
MqlTradeResult result = {};
|
||
|
|
|
||
|
|
request.action = TRADE_ACTION_DEAL;
|
||
|
|
request.symbol = symbol;
|
||
|
|
request.volume = volume;
|
||
|
|
request.type = order_type;
|
||
|
|
request.price = price;
|
||
|
|
request.deviation = slippage;
|
||
|
|
request.sl = sl;
|
||
|
|
request.tp = tp;
|
||
|
|
request.comment = comment;
|
||
|
|
request.magic = magic;
|
||
|
|
|
||
|
|
if(!OrderSend(request, result))
|
||
|
|
{
|
||
|
|
Print("OrderSend failed: ", GetLastError());
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if(result.retcode != TRADE_RETCODE_DONE)
|
||
|
|
{
|
||
|
|
Print("Order failed with retcode: ", result.retcode);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Position Modify function with error handling |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool PositionModify(ulong ticket, double sl, double tp)
|
||
|
|
{
|
||
|
|
MqlTradeRequest request = {};
|
||
|
|
MqlTradeResult result = {};
|
||
|
|
|
||
|
|
request.action = TRADE_ACTION_SLTP;
|
||
|
|
request.position = ticket;
|
||
|
|
request.sl = sl;
|
||
|
|
request.tp = tp;
|
||
|
|
|
||
|
|
if(!OrderSend(request, result))
|
||
|
|
{
|
||
|
|
Print("PositionModify failed: ", GetLastError());
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if(result.retcode != TRADE_RETCODE_DONE)
|
||
|
|
{
|
||
|
|
Print("Position modify failed with retcode: ", result.retcode);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|