Zenith-FX/ForexTrader_v2_MultiStrategy.mq5

1447 lines
47 KiB
MQL5

2025-11-14 03:55:03 +01:00
//+------------------------------------------------------------------+
//| ForexMaster_v2_MultiStrategy.mq5 |
//| Productivity-Focused Multi-Strategy EA |
//| Enhanced Risk Management System |
//+------------------------------------------------------------------+
#property copyright "MLQ5-EA Project v2.0"
#property link "https://github.com/simonokwundue-ops/MLQ5-EA"
#property version "2.00"
#property description "Advanced multi-strategy EA with portfolio management"
#property description "Targets 5-20 positions daily with 60-70% win rate"
#include <Trade\Trade.mqh>
#include <Trade\PositionInfo.mqh>
#include <Trade\AccountInfo.mqh>
//--- Global Objects
CTrade trade;
CPositionInfo positionInfo;
CAccountInfo accountInfo;
//--- Input Parameters
input group "=== Multi-Strategy Settings ==="
input bool UseMAStrategy = true; // Use MA Crossover Strategy
input bool UseRSIStrategy = true; // Use RSI Strategy
input bool UseBBStrategy = true; // Use Bollinger Bands Strategy
input bool UseMACDStrategy = true; // Use MACD Strategy
input int MinSignalScore = 60; // Minimum Signal Quality Score (0-100)
input group "=== Multi-Timeframe Analysis ==="
input bool UseMultiTimeframe = true; // Enable Multi-Timeframe Analysis
input ENUM_TIMEFRAMES TimeFrame1 = PERIOD_M15; // Timeframe 1 (Fast)
input ENUM_TIMEFRAMES TimeFrame2 = PERIOD_M30; // Timeframe 2 (Medium)
input ENUM_TIMEFRAMES TimeFrame3 = PERIOD_H1; // Timeframe 3 (Slow)
input int MinTFConfirmation = 2; // Min Timeframes for Confirmation (1-3)
input group "=== Moving Average Settings ==="
input int FastMA_Period = 10; // Fast MA Period
input int SlowMA_Period = 30; // Slow MA Period
input ENUM_MA_METHOD MA_Method = MODE_EMA; // MA Method
input group "=== RSI Settings ==="
input int RSI_Period = 14; // RSI Period
input double RSI_Oversold = 30.0; // RSI Oversold Level
input double RSI_Overbought = 70.0; // RSI Overbought Level
input group "=== Bollinger Bands Settings ==="
input int BB_Period = 20; // BB Period
input double BB_Deviation = 2.0; // BB Standard Deviation
input ENUM_APPLIED_PRICE BB_AppliedPrice = PRICE_CLOSE; // BB Applied Price
input group "=== MACD Settings ==="
input int MACD_FastEMA = 12; // MACD Fast EMA
input int MACD_SlowEMA = 26; // MACD Slow EMA
input int MACD_Signal = 9; // MACD Signal Period
input group "=== Portfolio Management ==="
input int MaxDailyTrades = 20; // Maximum Trades Per Day
input int MinDailyTrades = 5; // Minimum Target Trades Per Day
input int MaxConcurrentPositions = 5; // Max Concurrent Positions
input double MaxPortfolioRisk = 10.0; // Max Portfolio Risk (% of Balance)
input group "=== Risk Management ==="
input double BaseRiskPercent = 1.5; // Base Risk Per Trade (%)
input bool UseDynamicRisk = true; // Use Dynamic Risk Based on Win Rate
input double MinRiskPercent = 0.5; // Minimum Risk Per Trade (%)
input double MaxRiskPercent = 3.0; // Maximum Risk Per Trade (%)
input double StopLossPips = 40.0; // Stop Loss (Pips)
input double TakeProfitPips = 80.0; // Take Profit (Pips)
input group "=== Volatility-Based Sizing ==="
input bool UseATRSizing = true; // Use ATR for Position Sizing
input int ATR_Period = 14; // ATR Period
input double ATR_Multiplier = 2.0; // ATR Multiplier for SL
input group "=== Advanced Position Management ==="
input bool UseBreakeven = true; // Auto Move to Breakeven
input double BreakevenTriggerPips = 25.0; // Breakeven Trigger (Pips)
input double BreakevenOffsetPips = 5.0; // Breakeven Offset (Pips)
input bool UsePartialTP = true; // Use Partial Take Profit
input double PartialTP_Pips = 40.0; // First Partial TP (Pips)
input double PartialTP_Percent = 50.0; // Partial Close % (of position)
input bool UseTrailingStop = true; // Use Trailing Stop
input double TrailingStopPips = 30.0; // Trailing Stop Distance (Pips)
input double TrailingStepPips = 10.0; // Trailing Step (Pips)
input group "=== Time-Based Filters ==="
input bool UseTimeFilter = true; // Enable Time-of-Day Filter
input int LondonOpenHour = 7; // London Session Start
input int NewYorkOpenHour = 12; // New York Session Start
input int AsianCloseHour = 8; // Asian Session Close
input bool TradeAsianSession = false; // Trade During Asian Session
input bool AvoidNewsEvents = true; // Avoid Major News Times
input group "=== Money Management ==="
input double MinLotSize = 0.01; // Minimum Lot Size
input double MaxLotSize = 5.0; // Maximum Lot Size
input bool UseCompounding = true; // Use Compounding
input group "=== Expert Advisor Settings ==="
input int MagicNumber = 234567; // Magic Number
input string TradeComment = "ForexMasterV2"; // Trade Comment
input int Slippage = 10; // Slippage (Points)
//--- Global Variables
int handleFastMA_TF1, handleSlowMA_TF1;
int handleFastMA_TF2, handleSlowMA_TF2;
int handleFastMA_TF3, handleSlowMA_TF3;
int handleRSI_TF1, handleRSI_TF2, handleRSI_TF3;
int handleBB_TF1, handleBB_TF2, handleBB_TF3;
int handleMACD_TF1, handleMACD_TF2, handleMACD_TF3;
int handleATR;
double fastMA_TF1[], slowMA_TF1[], fastMA_TF2[], slowMA_TF2[], fastMA_TF3[], slowMA_TF3[];
double rsi_TF1[], rsi_TF2[], rsi_TF3[];
double bb_upper_TF1[], bb_middle_TF1[], bb_lower_TF1[];
double bb_upper_TF2[], bb_middle_TF2[], bb_lower_TF2[];
double bb_upper_TF3[], bb_middle_TF3[], bb_lower_TF3[];
double macd_main_TF1[], macd_signal_TF1[];
double macd_main_TF2[], macd_signal_TF2[];
double macd_main_TF3[], macd_signal_TF3[];
double atr[];
datetime lastBarTime;
datetime lastTradeTime;
int dailyTradeCount = 0;
datetime currentDay = 0;
double dailyProfitLoss = 0.0;
double totalWins = 0;
double totalTrades = 0;
double currentWinRate = 0.5; // Start at 50%
struct PositionTracker {
ulong ticket;
bool breakEvenSet;
bool partialTPTaken;
datetime openTime;
double openPrice;
double initialLots;
int signalScore;
};
PositionTracker openPositions[100];
int positionCount = 0;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- Setup trade object
trade.SetExpertMagicNumber(MagicNumber);
trade.SetDeviationInPoints(Slippage);
trade.SetTypeFilling(ORDER_FILLING_FOK);
trade.SetAsyncMode(false);
//--- Validate parameters
if(!ValidateParameters())
return INIT_PARAMETERS_INCORRECT;
//--- Initialize indicators
if(!InitializeIndicators())
return INIT_FAILED;
//--- Set arrays as series
SetArraysAsSeries();
//--- Initialize variables
lastBarTime = 0;
lastTradeTime = 0;
currentDay = 0;
dailyTradeCount = 0;
//--- Load historical win rate if available
LoadWinRateHistory();
Print("=== ForexMaster v2.0 Multi-Strategy EA Initialized ===");
Print("Strategies Active: MA=", UseMAStrategy, " RSI=", UseRSIStrategy,
" BB=", UseBBStrategy, " MACD=", UseMACDStrategy);
Print("Multi-Timeframe: ", UseMultiTimeframe, " | Min TF Confirmation: ", MinTFConfirmation);
Print("Daily Trade Target: ", MinDailyTrades, "-", MaxDailyTrades);
Print("Max Concurrent Positions: ", MaxConcurrentPositions);
Print("Base Risk: ", BaseRiskPercent, "% | Dynamic Risk: ", UseDynamicRisk);
Print("Advanced Features: Breakeven=", UseBreakeven, " PartialTP=", UsePartialTP, " Trailing=", UseTrailingStop);
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- Save win rate history
SaveWinRateHistory();
//--- Release all indicator handles
ReleaseIndicators();
Print("ForexMaster v2.0 deinitialized. Reason: ", reason);
Print("Final Win Rate: ", DoubleToString(currentWinRate * 100, 2), "%");
Print("Total Trades Today: ", dailyTradeCount);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- Check for new bar
if(!IsNewBar())
return;
//--- Reset daily counter
CheckAndResetDailyCounter();
//--- Update all indicators
if(!UpdateAllIndicators())
return;
//--- Manage existing positions
ManageAllPositions();
//--- Check trading conditions
if(!CanTrade())
return;
//--- Analyze and execute trades
AnalyzeAndTrade();
}
//+------------------------------------------------------------------+
//| Check if new bar has formed |
//+------------------------------------------------------------------+
bool IsNewBar()
{
datetime currentBarTime = iTime(_Symbol, PERIOD_CURRENT, 0);
if(lastBarTime != currentBarTime)
{
lastBarTime = currentBarTime;
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Check and reset daily counter |
//+------------------------------------------------------------------+
void CheckAndResetDailyCounter()
{
MqlDateTime dt;
TimeToStruct(TimeCurrent(), dt);
datetime today = StringToTime(IntegerToString(dt.year) + "." +
IntegerToString(dt.mon) + "." +
IntegerToString(dt.day));
if(currentDay != today)
{
if(currentDay != 0)
{
Print("=== Daily Summary ===");
Print("Date: ", TimeToString(currentDay, TIME_DATE));
Print("Total Trades: ", dailyTradeCount);
Print("Daily P/L: ", DoubleToString(dailyProfitLoss, 2));
Print("Win Rate: ", DoubleToString(currentWinRate * 100, 2), "%");
}
currentDay = today;
dailyTradeCount = 0;
dailyProfitLoss = 0.0;
}
}
//+------------------------------------------------------------------+
//| Validate input parameters |
//+------------------------------------------------------------------+
bool ValidateParameters()
{
if(FastMA_Period >= SlowMA_Period)
{
Print("ERROR: Fast MA must be less than Slow MA");
return false;
}
if(MinSignalScore < 0 || MinSignalScore > 100)
{
Print("ERROR: Signal Score must be between 0-100");
return false;
}
if(MaxDailyTrades < MinDailyTrades)
{
Print("ERROR: Max daily trades must be >= Min daily trades");
return false;
}
if(BaseRiskPercent < MinRiskPercent || BaseRiskPercent > MaxRiskPercent)
{
Print("ERROR: Base risk must be between Min and Max risk");
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| Initialize all indicators |
//+------------------------------------------------------------------+
bool InitializeIndicators()
{
//--- Initialize MA indicators
if(UseMAStrategy)
{
handleFastMA_TF1 = iMA(_Symbol, TimeFrame1, FastMA_Period, 0, MA_Method, PRICE_CLOSE);
handleSlowMA_TF1 = iMA(_Symbol, TimeFrame1, SlowMA_Period, 0, MA_Method, PRICE_CLOSE);
if(UseMultiTimeframe)
{
handleFastMA_TF2 = iMA(_Symbol, TimeFrame2, FastMA_Period, 0, MA_Method, PRICE_CLOSE);
handleSlowMA_TF2 = iMA(_Symbol, TimeFrame2, SlowMA_Period, 0, MA_Method, PRICE_CLOSE);
handleFastMA_TF3 = iMA(_Symbol, TimeFrame3, FastMA_Period, 0, MA_Method, PRICE_CLOSE);
handleSlowMA_TF3 = iMA(_Symbol, TimeFrame3, SlowMA_Period, 0, MA_Method, PRICE_CLOSE);
}
if(handleFastMA_TF1 == INVALID_HANDLE || handleSlowMA_TF1 == INVALID_HANDLE)
{
Print("ERROR: Failed to create MA indicators");
return false;
}
}
//--- Initialize RSI indicators
if(UseRSIStrategy)
{
handleRSI_TF1 = iRSI(_Symbol, TimeFrame1, RSI_Period, PRICE_CLOSE);
if(UseMultiTimeframe)
{
handleRSI_TF2 = iRSI(_Symbol, TimeFrame2, RSI_Period, PRICE_CLOSE);
handleRSI_TF3 = iRSI(_Symbol, TimeFrame3, RSI_Period, PRICE_CLOSE);
}
if(handleRSI_TF1 == INVALID_HANDLE)
{
Print("ERROR: Failed to create RSI indicator");
return false;
}
}
//--- Initialize Bollinger Bands indicators
if(UseBBStrategy)
{
handleBB_TF1 = iBands(_Symbol, TimeFrame1, BB_Period, 0, BB_Deviation, BB_AppliedPrice);
if(UseMultiTimeframe)
{
handleBB_TF2 = iBands(_Symbol, TimeFrame2, BB_Period, 0, BB_Deviation, BB_AppliedPrice);
handleBB_TF3 = iBands(_Symbol, TimeFrame3, BB_Period, 0, BB_Deviation, BB_AppliedPrice);
}
if(handleBB_TF1 == INVALID_HANDLE)
{
Print("ERROR: Failed to create Bollinger Bands indicator");
return false;
}
}
//--- Initialize MACD indicators
if(UseMACDStrategy)
{
handleMACD_TF1 = iMACD(_Symbol, TimeFrame1, MACD_FastEMA, MACD_SlowEMA, MACD_Signal, PRICE_CLOSE);
if(UseMultiTimeframe)
{
handleMACD_TF2 = iMACD(_Symbol, TimeFrame2, MACD_FastEMA, MACD_SlowEMA, MACD_Signal, PRICE_CLOSE);
handleMACD_TF3 = iMACD(_Symbol, TimeFrame3, MACD_FastEMA, MACD_SlowEMA, MACD_Signal, PRICE_CLOSE);
}
if(handleMACD_TF1 == INVALID_HANDLE)
{
Print("ERROR: Failed to create MACD indicator");
return false;
}
}
//--- Initialize ATR for volatility-based sizing
if(UseATRSizing)
{
handleATR = iATR(_Symbol, PERIOD_CURRENT, ATR_Period);
if(handleATR == INVALID_HANDLE)
{
Print("ERROR: Failed to create ATR indicator");
return false;
}
}
return true;
}
//+------------------------------------------------------------------+
//| Set all arrays as series |
//+------------------------------------------------------------------+
void SetArraysAsSeries()
{
ArraySetAsSeries(fastMA_TF1, true);
ArraySetAsSeries(slowMA_TF1, true);
ArraySetAsSeries(fastMA_TF2, true);
ArraySetAsSeries(slowMA_TF2, true);
ArraySetAsSeries(fastMA_TF3, true);
ArraySetAsSeries(slowMA_TF3, true);
ArraySetAsSeries(rsi_TF1, true);
ArraySetAsSeries(rsi_TF2, true);
ArraySetAsSeries(rsi_TF3, true);
ArraySetAsSeries(bb_upper_TF1, true);
ArraySetAsSeries(bb_middle_TF1, true);
ArraySetAsSeries(bb_lower_TF1, true);
ArraySetAsSeries(bb_upper_TF2, true);
ArraySetAsSeries(bb_middle_TF2, true);
ArraySetAsSeries(bb_lower_TF2, true);
ArraySetAsSeries(bb_upper_TF3, true);
ArraySetAsSeries(bb_middle_TF3, true);
ArraySetAsSeries(bb_lower_TF3, true);
ArraySetAsSeries(macd_main_TF1, true);
ArraySetAsSeries(macd_signal_TF1, true);
ArraySetAsSeries(macd_main_TF2, true);
ArraySetAsSeries(macd_signal_TF2, true);
ArraySetAsSeries(macd_main_TF3, true);
ArraySetAsSeries(macd_signal_TF3, true);
ArraySetAsSeries(atr, true);
}
//+------------------------------------------------------------------+
//| Update all indicator buffers |
//+------------------------------------------------------------------+
bool UpdateAllIndicators()
{
//--- Update MA indicators
if(UseMAStrategy)
{
if(CopyBuffer(handleFastMA_TF1, 0, 0, 3, fastMA_TF1) < 3) return false;
if(CopyBuffer(handleSlowMA_TF1, 0, 0, 3, slowMA_TF1) < 3) return false;
if(UseMultiTimeframe)
{
if(CopyBuffer(handleFastMA_TF2, 0, 0, 3, fastMA_TF2) < 3) return false;
if(CopyBuffer(handleSlowMA_TF2, 0, 0, 3, slowMA_TF2) < 3) return false;
if(CopyBuffer(handleFastMA_TF3, 0, 0, 3, fastMA_TF3) < 3) return false;
if(CopyBuffer(handleSlowMA_TF3, 0, 0, 3, slowMA_TF3) < 3) return false;
}
}
//--- Update RSI indicators
if(UseRSIStrategy)
{
if(CopyBuffer(handleRSI_TF1, 0, 0, 3, rsi_TF1) < 3) return false;
if(UseMultiTimeframe)
{
if(CopyBuffer(handleRSI_TF2, 0, 0, 3, rsi_TF2) < 3) return false;
if(CopyBuffer(handleRSI_TF3, 0, 0, 3, rsi_TF3) < 3) return false;
}
}
//--- Update Bollinger Bands indicators
if(UseBBStrategy)
{
if(CopyBuffer(handleBB_TF1, 0, 0, 3, bb_upper_TF1) < 3) return false;
if(CopyBuffer(handleBB_TF1, 1, 0, 3, bb_middle_TF1) < 3) return false;
if(CopyBuffer(handleBB_TF1, 2, 0, 3, bb_lower_TF1) < 3) return false;
if(UseMultiTimeframe)
{
if(CopyBuffer(handleBB_TF2, 0, 0, 3, bb_upper_TF2) < 3) return false;
if(CopyBuffer(handleBB_TF2, 1, 0, 3, bb_middle_TF2) < 3) return false;
if(CopyBuffer(handleBB_TF2, 2, 0, 3, bb_lower_TF2) < 3) return false;
if(CopyBuffer(handleBB_TF3, 0, 0, 3, bb_upper_TF3) < 3) return false;
if(CopyBuffer(handleBB_TF3, 1, 0, 3, bb_middle_TF3) < 3) return false;
if(CopyBuffer(handleBB_TF3, 2, 0, 3, bb_lower_TF3) < 3) return false;
}
}
//--- Update MACD indicators
if(UseMACDStrategy)
{
if(CopyBuffer(handleMACD_TF1, 0, 0, 3, macd_main_TF1) < 3) return false;
if(CopyBuffer(handleMACD_TF1, 1, 0, 3, macd_signal_TF1) < 3) return false;
if(UseMultiTimeframe)
{
if(CopyBuffer(handleMACD_TF2, 0, 0, 3, macd_main_TF2) < 3) return false;
if(CopyBuffer(handleMACD_TF2, 1, 0, 3, macd_signal_TF2) < 3) return false;
if(CopyBuffer(handleMACD_TF3, 0, 0, 3, macd_main_TF3) < 3) return false;
if(CopyBuffer(handleMACD_TF3, 1, 0, 3, macd_signal_TF3) < 3) return false;
}
}
//--- Update ATR
if(UseATRSizing)
{
if(CopyBuffer(handleATR, 0, 0, 3, atr) < 3) return false;
}
return true;
}
//+------------------------------------------------------------------+
//| Check if can trade |
//+------------------------------------------------------------------+
bool CanTrade()
{
//--- Check daily trade limit
if(dailyTradeCount >= MaxDailyTrades)
{
return false;
}
//--- Check concurrent positions
if(CountOwnPositions() >= MaxConcurrentPositions)
{
return false;
}
//--- Check portfolio risk
if(GetCurrentPortfolioRisk() >= MaxPortfolioRisk)
{
return false;
}
//--- Check time filter
if(UseTimeFilter && !IsGoodTradingTime())
{
return false;
}
//--- Check trading allowed
if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) || !MQLInfoInteger(MQL_TRADE_ALLOWED))
{
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| Check if current time is good for trading |
//+------------------------------------------------------------------+
bool IsGoodTradingTime()
{
MqlDateTime dt;
TimeToStruct(TimeCurrent(), dt);
int currentHour = dt.hour;
//--- Avoid Asian session if disabled
if(!TradeAsianSession && currentHour >= 0 && currentHour < AsianCloseHour)
{
return false;
}
//--- Favor London and New York session opens (high volatility/opportunity)
bool isLondonOpen = (currentHour >= LondonOpenHour && currentHour < LondonOpenHour + 4);
bool isNYOpen = (currentHour >= NewYorkOpenHour && currentHour < NewYorkOpenHour + 4);
bool isOverlap = (currentHour >= NewYorkOpenHour && currentHour < 16); // London-NY overlap
if(isLondonOpen || isNYOpen || isOverlap)
{
return true;
}
//--- Allow trading during other hours but with higher signal requirements
return true;
}
//+------------------------------------------------------------------+
//| Analyze market and execute trades |
//+------------------------------------------------------------------+
void AnalyzeAndTrade()
{
//--- Get trading signals from all strategies
int signalDirection = 0; // 1=Buy, -1=Sell, 0=No signal
int signalScore = 0;
CalculateSignals(signalDirection, signalScore);
//--- Check if signal meets minimum quality threshold
if(signalScore < MinSignalScore)
{
return;
}
//--- Execute trade based on signal
if(signalDirection == 1)
{
ExecuteBuyTrade(signalScore);
}
else if(signalDirection == -1)
{
ExecuteSellTrade(signalScore);
}
}
//+------------------------------------------------------------------+
//| Calculate signals from all strategies |
//+------------------------------------------------------------------+
void CalculateSignals(int &direction, int &score)
{
int buySignals = 0;
int sellSignals = 0;
int totalWeight = 0;
//--- MA Strategy Signals
if(UseMAStrategy)
{
int maSignal = GetMASignal();
int maWeight = 25;
if(maSignal == 1) buySignals += maWeight;
else if(maSignal == -1) sellSignals += maWeight;
totalWeight += maWeight;
}
//--- RSI Strategy Signals
if(UseRSIStrategy)
{
int rsiSignal = GetRSISignal();
int rsiWeight = 25;
if(rsiSignal == 1) buySignals += rsiWeight;
else if(rsiSignal == -1) sellSignals += rsiWeight;
totalWeight += rsiWeight;
}
//--- Bollinger Bands Strategy Signals
if(UseBBStrategy)
{
int bbSignal = GetBBSignal();
int bbWeight = 25;
if(bbSignal == 1) buySignals += bbWeight;
else if(bbSignal == -1) sellSignals += bbWeight;
totalWeight += bbWeight;
}
//--- MACD Strategy Signals
if(UseMACDStrategy)
{
int macdSignal = GetMACDSignal();
int macdWeight = 25;
if(macdSignal == 1) buySignals += macdWeight;
else if(macdSignal == -1) sellSignals += macdWeight;
totalWeight += macdWeight;
}
//--- Calculate final signal direction and score
if(buySignals > sellSignals)
{
direction = 1;
score = (int)((double)buySignals / totalWeight * 100);
}
else if(sellSignals > buySignals)
{
direction = -1;
score = (int)((double)sellSignals / totalWeight * 100);
}
else
{
direction = 0;
score = 0;
}
}
//+------------------------------------------------------------------+
//| Get MA strategy signal |
//+------------------------------------------------------------------+
int GetMASignal()
{
int tfConfirmed = 0;
int buyVotes = 0;
int sellVotes = 0;
//--- Check TF1
bool bullishCross_TF1 = (fastMA_TF1[1] > slowMA_TF1[1]) && (fastMA_TF1[2] <= slowMA_TF1[2]);
bool bearishCross_TF1 = (fastMA_TF1[1] < slowMA_TF1[1]) && (fastMA_TF1[2] >= slowMA_TF1[2]);
bool bullishTrend_TF1 = fastMA_TF1[0] > slowMA_TF1[0];
bool bearishTrend_TF1 = fastMA_TF1[0] < slowMA_TF1[0];
if((bullishCross_TF1 || bullishTrend_TF1) && fastMA_TF1[0] > slowMA_TF1[0])
{
buyVotes++;
tfConfirmed++;
}
else if((bearishCross_TF1 || bearishTrend_TF1) && fastMA_TF1[0] < slowMA_TF1[0])
{
sellVotes++;
tfConfirmed++;
}
//--- Check TF2 and TF3 if multi-timeframe enabled
if(UseMultiTimeframe)
{
bool bullishTrend_TF2 = fastMA_TF2[0] > slowMA_TF2[0];
bool bearishTrend_TF2 = fastMA_TF2[0] < slowMA_TF2[0];
if(bullishTrend_TF2)
{
buyVotes++;
tfConfirmed++;
}
else if(bearishTrend_TF2)
{
sellVotes++;
tfConfirmed++;
}
bool bullishTrend_TF3 = fastMA_TF3[0] > slowMA_TF3[0];
bool bearishTrend_TF3 = fastMA_TF3[0] < slowMA_TF3[0];
if(bullishTrend_TF3)
{
buyVotes++;
}
else if(bearishTrend_TF3)
{
sellVotes++;
}
}
//--- Require minimum timeframe confirmation
if(UseMultiTimeframe && tfConfirmed < MinTFConfirmation)
{
return 0;
}
//--- Return signal
if(buyVotes > sellVotes) return 1;
else if(sellVotes > buyVotes) return -1;
return 0;
}
//+------------------------------------------------------------------+
//| Get RSI strategy signal |
//+------------------------------------------------------------------+
int GetRSISignal()
{
int buyVotes = 0;
int sellVotes = 0;
//--- TF1 RSI
bool oversold_TF1 = rsi_TF1[0] < RSI_Oversold;
bool overbought_TF1 = rsi_TF1[0] > RSI_Overbought;
bool risingFromOversold_TF1 = rsi_TF1[0] > RSI_Oversold && rsi_TF1[1] <= RSI_Oversold;
bool fallingFromOverbought_TF1 = rsi_TF1[0] < RSI_Overbought && rsi_TF1[1] >= RSI_Overbought;
if(risingFromOversold_TF1 || (oversold_TF1 && rsi_TF1[0] > rsi_TF1[1]))
{
buyVotes++;
}
else if(fallingFromOverbought_TF1 || (overbought_TF1 && rsi_TF1[0] < rsi_TF1[1]))
{
sellVotes++;
}
//--- TF2 and TF3 confirmation
if(UseMultiTimeframe)
{
if(rsi_TF2[0] < 50 && rsi_TF2[0] > rsi_TF2[1])
buyVotes++;
else if(rsi_TF2[0] > 50 && rsi_TF2[0] < rsi_TF2[1])
sellVotes++;
if(rsi_TF3[0] < 50)
buyVotes++;
else if(rsi_TF3[0] > 50)
sellVotes++;
}
if(buyVotes > sellVotes) return 1;
else if(sellVotes > buyVotes) return -1;
return 0;
}
//+------------------------------------------------------------------+
//| Get Bollinger Bands strategy signal |
//+------------------------------------------------------------------+
int GetBBSignal()
{
double currentPrice = iClose(_Symbol, TimeFrame1, 0);
int buyVotes = 0;
int sellVotes = 0;
//--- TF1 BB
bool priceBelowLower_TF1 = currentPrice < bb_lower_TF1[0];
bool priceAboveUpper_TF1 = currentPrice > bb_upper_TF1[0];
bool priceRisingFromLower_TF1 = currentPrice > bb_lower_TF1[0] &&
iClose(_Symbol, TimeFrame1, 1) <= bb_lower_TF1[1];
bool priceFallingFromUpper_TF1 = currentPrice < bb_upper_TF1[0] &&
iClose(_Symbol, TimeFrame1, 1) >= bb_upper_TF1[1];
if(priceRisingFromLower_TF1 || priceBelowLower_TF1)
{
buyVotes++;
}
else if(priceFallingFromUpper_TF1 || priceAboveUpper_TF1)
{
sellVotes++;
}
//--- TF2 and TF3 confirmation
if(UseMultiTimeframe)
{
if(currentPrice < bb_middle_TF2[0])
buyVotes++;
else if(currentPrice > bb_middle_TF2[0])
sellVotes++;
if(currentPrice < bb_middle_TF3[0])
buyVotes++;
else if(currentPrice > bb_middle_TF3[0])
sellVotes++;
}
if(buyVotes > sellVotes) return 1;
else if(sellVotes > buyVotes) return -1;
return 0;
}
//+------------------------------------------------------------------+
//| Get MACD strategy signal |
//+------------------------------------------------------------------+
int GetMACDSignal()
{
int buyVotes = 0;
int sellVotes = 0;
//--- TF1 MACD
bool bullishCross_TF1 = (macd_main_TF1[1] > macd_signal_TF1[1]) &&
(macd_main_TF1[2] <= macd_signal_TF1[2]);
bool bearishCross_TF1 = (macd_main_TF1[1] < macd_signal_TF1[1]) &&
(macd_main_TF1[2] >= macd_signal_TF1[2]);
bool bullish_TF1 = macd_main_TF1[0] > macd_signal_TF1[0] && macd_main_TF1[0] < 0;
bool bearish_TF1 = macd_main_TF1[0] < macd_signal_TF1[0] && macd_main_TF1[0] > 0;
if(bullishCross_TF1 || bullish_TF1)
{
buyVotes++;
}
else if(bearishCross_TF1 || bearish_TF1)
{
sellVotes++;
}
//--- TF2 and TF3 confirmation
if(UseMultiTimeframe)
{
if(macd_main_TF2[0] > macd_signal_TF2[0])
buyVotes++;
else if(macd_main_TF2[0] < macd_signal_TF2[0])
sellVotes++;
if(macd_main_TF3[0] > macd_signal_TF3[0])
buyVotes++;
else if(macd_main_TF3[0] < macd_signal_TF3[0])
sellVotes++;
}
if(buyVotes > sellVotes) return 1;
else if(sellVotes > buyVotes) return -1;
return 0;
}
//+------------------------------------------------------------------+
//| Execute buy trade |
//+------------------------------------------------------------------+
void ExecuteBuyTrade(int signalScore)
{
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double sl = CalculateStopLoss(ORDER_TYPE_BUY, ask);
double tp = CalculateTakeProfit(ORDER_TYPE_BUY, ask);
double lots = CalculateLotSize(ask, sl);
//--- Normalize values
sl = NormalizeDouble(sl, _Digits);
tp = NormalizeDouble(tp, _Digits);
lots = NormalizeLot(lots);
//--- Execute trade
if(trade.Buy(lots, _Symbol, ask, sl, tp, TradeComment + "_S" + IntegerToString(signalScore)))
{
ulong ticket = trade.ResultOrder();
dailyTradeCount++;
lastTradeTime = TimeCurrent();
//--- Track position
AddPositionToTracker(ticket, lots, ask, signalScore);
Print("BUY order executed | Ticket: ", ticket, " | Lots: ", lots,
" | Price: ", ask, " | SL: ", sl, " | TP: ", tp, " | Score: ", signalScore);
}
else
{
Print("BUY order failed | Error: ", GetLastError());
}
}
//+------------------------------------------------------------------+
//| Execute sell trade |
//+------------------------------------------------------------------+
void ExecuteSellTrade(int signalScore)
{
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double sl = CalculateStopLoss(ORDER_TYPE_SELL, bid);
double tp = CalculateTakeProfit(ORDER_TYPE_SELL, bid);
double lots = CalculateLotSize(bid, sl);
//--- Normalize values
sl = NormalizeDouble(sl, _Digits);
tp = NormalizeDouble(tp, _Digits);
lots = NormalizeLot(lots);
//--- Execute trade
if(trade.Sell(lots, _Symbol, bid, sl, tp, TradeComment + "_S" + IntegerToString(signalScore)))
{
ulong ticket = trade.ResultOrder();
dailyTradeCount++;
lastTradeTime = TimeCurrent();
//--- Track position
AddPositionToTracker(ticket, lots, bid, signalScore);
Print("SELL order executed | Ticket: ", ticket, " | Lots: ", lots,
" | Price: ", bid, " | SL: ", sl, " | TP: ", tp, " | Score: ", signalScore);
}
else
{
Print("SELL order failed | Error: ", GetLastError());
}
}
//+------------------------------------------------------------------+
//| Calculate stop loss |
//+------------------------------------------------------------------+
double CalculateStopLoss(ENUM_ORDER_TYPE orderType, double price)
{
double sl = 0;
double slDistance = StopLossPips * GetPipValue();
//--- Use ATR-based SL if enabled
if(UseATRSizing && atr[0] > 0)
{
slDistance = atr[0] * ATR_Multiplier;
}
if(orderType == ORDER_TYPE_BUY)
{
sl = price - slDistance;
}
else if(orderType == ORDER_TYPE_SELL)
{
sl = price + slDistance;
}
return sl;
}
//+------------------------------------------------------------------+
//| Calculate take profit |
//+------------------------------------------------------------------+
double CalculateTakeProfit(ENUM_ORDER_TYPE orderType, double price)
{
double tp = 0;
double tpDistance = TakeProfitPips * GetPipValue();
//--- Use ATR-based TP if enabled (2x SL for risk-reward ratio)
if(UseATRSizing && atr[0] > 0)
{
tpDistance = atr[0] * ATR_Multiplier * 2.0;
}
if(orderType == ORDER_TYPE_BUY)
{
tp = price + tpDistance;
}
else if(orderType == ORDER_TYPE_SELL)
{
tp = price - tpDistance;
}
return tp;
}
//+------------------------------------------------------------------+
//| Calculate lot size based on risk |
//+------------------------------------------------------------------+
double CalculateLotSize(double entryPrice, double stopLoss)
{
double riskPercent = BaseRiskPercent;
//--- Adjust risk based on win rate if dynamic risk enabled
if(UseDynamicRisk)
{
if(currentWinRate >= 0.65)
riskPercent = MaxRiskPercent; // Increase risk when winning
else if(currentWinRate <= 0.45)
riskPercent = MinRiskPercent; // Decrease risk when losing
}
//--- Calculate risk amount
double balance = UseCompounding ? accountInfo.Balance() : accountInfo.Equity();
double riskAmount = balance * (riskPercent / 100.0);
//--- Calculate lot size
double slDistance = MathAbs(entryPrice - stopLoss);
double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
if(slDistance == 0 || tickSize == 0)
return MinLotSize;
double ticksDistance = slDistance / tickSize;
double riskPerLot = ticksDistance * tickValue;
if(riskPerLot == 0)
return MinLotSize;
double lots = riskAmount / riskPerLot;
//--- Apply limits
if(lots > MaxLotSize)
lots = MaxLotSize;
if(lots < MinLotSize)
lots = MinLotSize;
return lots;
}
//+------------------------------------------------------------------+
//| Normalize lot size |
//+------------------------------------------------------------------+
double NormalizeLot(double lots)
{
double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
if(MinLotSize > minLot)
minLot = MinLotSize;
if(MaxLotSize < maxLot)
maxLot = MaxLotSize;
lots = MathFloor(lots / lotStep) * lotStep;
if(lots < minLot)
lots = minLot;
if(lots > maxLot)
lots = maxLot;
return NormalizeDouble(lots, 2);
}
//+------------------------------------------------------------------+
//| Get pip value |
//+------------------------------------------------------------------+
double GetPipValue()
{
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
if(digits == 3 || digits == 5)
return point * 10;
else
return point * 1;
}
//+------------------------------------------------------------------+
//| Manage all open positions |
//+------------------------------------------------------------------+
void ManageAllPositions()
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(positionInfo.SelectByIndex(i))
{
if(positionInfo.Symbol() == _Symbol && positionInfo.Magic() == MagicNumber)
{
ulong ticket = positionInfo.Ticket();
//--- Apply position management
if(UseBreakeven)
ManageBreakeven(ticket);
if(UsePartialTP)
ManagePartialTP(ticket);
if(UseTrailingStop)
ManageTrailingStop(ticket);
}
}
}
//--- Update win rate
UpdateWinRate();
}
//+------------------------------------------------------------------+
//| Manage breakeven for position |
//+------------------------------------------------------------------+
void ManageBreakeven(ulong ticket)
{
if(!positionInfo.SelectByTicket(ticket))
return;
//--- Check if already at breakeven
int trackerIndex = FindPositionInTracker(ticket);
if(trackerIndex >= 0 && openPositions[trackerIndex].breakEvenSet)
return;
double openPrice = positionInfo.PriceOpen();
double currentSL = positionInfo.StopLoss();
double currentTP = positionInfo.TakeProfit();
ENUM_POSITION_TYPE posType = positionInfo.PositionType();
double currentPrice = posType == POSITION_TYPE_BUY ?
SymbolInfoDouble(_Symbol, SYMBOL_BID) :
SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double triggerDistance = BreakevenTriggerPips * GetPipValue();
double offsetDistance = BreakevenOffsetPips * GetPipValue();
//--- Check if profit reached trigger level
bool triggerReached = false;
if(posType == POSITION_TYPE_BUY)
{
triggerReached = (currentPrice >= openPrice + triggerDistance);
}
else
{
triggerReached = (currentPrice <= openPrice - triggerDistance);
}
if(triggerReached)
{
double newSL = posType == POSITION_TYPE_BUY ?
openPrice + offsetDistance :
openPrice - offsetDistance;
newSL = NormalizeDouble(newSL, _Digits);
if(trade.PositionModify(ticket, newSL, currentTP))
{
if(trackerIndex >= 0)
openPositions[trackerIndex].breakEvenSet = true;
Print("Breakeven set for ticket: ", ticket, " | New SL: ", newSL);
}
}
}
//+------------------------------------------------------------------+
//| Manage partial take profit |
//+------------------------------------------------------------------+
void ManagePartialTP(ulong ticket)
{
if(!positionInfo.SelectByTicket(ticket))
return;
//--- Check if partial TP already taken
int trackerIndex = FindPositionInTracker(ticket);
if(trackerIndex >= 0 && openPositions[trackerIndex].partialTPTaken)
return;
double openPrice = positionInfo.PriceOpen();
ENUM_POSITION_TYPE posType = positionInfo.PositionType();
double currentPrice = posType == POSITION_TYPE_BUY ?
SymbolInfoDouble(_Symbol, SYMBOL_BID) :
SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double partialTPDistance = PartialTP_Pips * GetPipValue();
//--- Check if partial TP level reached
bool tpReached = false;
if(posType == POSITION_TYPE_BUY)
{
tpReached = (currentPrice >= openPrice + partialTPDistance);
}
else
{
tpReached = (currentPrice <= openPrice - partialTPDistance);
}
if(tpReached)
{
double currentVolume = positionInfo.Volume();
double closeVolume = NormalizeLot(currentVolume * (PartialTP_Percent / 100.0));
if(closeVolume >= SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN))
{
if(trade.PositionClosePartial(ticket, closeVolume))
{
if(trackerIndex >= 0)
openPositions[trackerIndex].partialTPTaken = true;
Print("Partial TP taken for ticket: ", ticket, " | Volume: ", closeVolume);
}
}
}
}
//+------------------------------------------------------------------+
//| Manage trailing stop |
//+------------------------------------------------------------------+
void ManageTrailingStop(ulong ticket)
{
if(!positionInfo.SelectByTicket(ticket))
return;
double openPrice = positionInfo.PriceOpen();
double currentSL = positionInfo.StopLoss();
double currentTP = positionInfo.TakeProfit();
ENUM_POSITION_TYPE posType = positionInfo.PositionType();
double currentPrice = posType == POSITION_TYPE_BUY ?
SymbolInfoDouble(_Symbol, SYMBOL_BID) :
SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double trailDistance = TrailingStopPips * GetPipValue();
double trailStep = TrailingStepPips * GetPipValue();
bool shouldModify = false;
double newSL = currentSL;
if(posType == POSITION_TYPE_BUY)
{
newSL = currentPrice - trailDistance;
if(newSL > currentSL + trailStep && newSL > openPrice)
{
shouldModify = true;
}
}
else
{
newSL = currentPrice + trailDistance;
if((newSL < currentSL - trailStep || currentSL == 0) && newSL < openPrice)
{
shouldModify = true;
}
}
if(shouldModify)
{
newSL = NormalizeDouble(newSL, _Digits);
if(trade.PositionModify(ticket, newSL, currentTP))
{
Print("Trailing stop updated for ticket: ", ticket, " | New SL: ", newSL);
}
}
}
//+------------------------------------------------------------------+
//| Count own positions |
//+------------------------------------------------------------------+
int CountOwnPositions()
{
int count = 0;
for(int i = 0; i < PositionsTotal(); i++)
{
if(positionInfo.SelectByIndex(i))
{
if(positionInfo.Symbol() == _Symbol && positionInfo.Magic() == MagicNumber)
{
count++;
}
}
}
return count;
}
//+------------------------------------------------------------------+
//| Get current portfolio risk |
//+------------------------------------------------------------------+
double GetCurrentPortfolioRisk()
{
double totalRisk = 0.0;
double balance = accountInfo.Balance();
for(int i = 0; i < PositionsTotal(); i++)
{
if(positionInfo.SelectByIndex(i))
{
if(positionInfo.Symbol() == _Symbol && positionInfo.Magic() == MagicNumber)
{
double openPrice = positionInfo.PriceOpen();
double sl = positionInfo.StopLoss();
double volume = positionInfo.Volume();
if(sl != 0)
{
double slDistance = MathAbs(openPrice - sl);
double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
double positionRisk = (slDistance / tickSize) * tickValue * volume;
totalRisk += positionRisk;
}
}
}
}
return (totalRisk / balance) * 100.0;
}
//+------------------------------------------------------------------+
//| Add position to tracker |
//+------------------------------------------------------------------+
void AddPositionToTracker(ulong ticket, double lots, double price, int score)
{
if(positionCount < 100)
{
openPositions[positionCount].ticket = ticket;
openPositions[positionCount].breakEvenSet = false;
openPositions[positionCount].partialTPTaken = false;
openPositions[positionCount].openTime = TimeCurrent();
openPositions[positionCount].openPrice = price;
openPositions[positionCount].initialLots = lots;
openPositions[positionCount].signalScore = score;
positionCount++;
}
}
//+------------------------------------------------------------------+
//| Find position in tracker |
//+------------------------------------------------------------------+
int FindPositionInTracker(ulong ticket)
{
for(int i = 0; i < positionCount; i++)
{
if(openPositions[i].ticket == ticket)
return i;
}
return -1;
}
//+------------------------------------------------------------------+
//| Update win rate |
//+------------------------------------------------------------------+
void UpdateWinRate()
{
int totalClosed = 0;
int winners = 0;
//--- Count closed positions from history
HistorySelect(0, TimeCurrent());
for(int i = 0; i < HistoryDealsTotal(); i++)
{
ulong ticket = HistoryDealGetTicket(i);
if(HistoryDealGetInteger(ticket, DEAL_MAGIC) == MagicNumber &&
HistoryDealGetString(ticket, DEAL_SYMBOL) == _Symbol &&
HistoryDealGetInteger(ticket, DEAL_ENTRY) == DEAL_ENTRY_OUT)
{
double profit = HistoryDealGetDouble(ticket, DEAL_PROFIT);
if(profit > 0)
winners++;
totalClosed++;
}
}
if(totalClosed > 0)
{
currentWinRate = (double)winners / totalClosed;
totalWins = winners;
totalTrades = totalClosed;
}
}
//+------------------------------------------------------------------+
//| Load win rate history |
//+------------------------------------------------------------------+
void LoadWinRateHistory()
{
//--- Load from file or global variable if available
if(GlobalVariableCheck("MLQ5_WinRate_" + _Symbol))
{
currentWinRate = GlobalVariableGet("MLQ5_WinRate_" + _Symbol);
Print("Loaded historical win rate: ", DoubleToString(currentWinRate * 100, 2), "%");
}
}
//+------------------------------------------------------------------+
//| Save win rate history |
//+------------------------------------------------------------------+
void SaveWinRateHistory()
{
GlobalVariableSet("MLQ5_WinRate_" + _Symbol, currentWinRate);
Print("Saved win rate: ", DoubleToString(currentWinRate * 100, 2), "%");
}
//+------------------------------------------------------------------+
//| Release all indicator handles |
//+------------------------------------------------------------------+
void ReleaseIndicators()
{
if(handleFastMA_TF1 != INVALID_HANDLE) IndicatorRelease(handleFastMA_TF1);
if(handleSlowMA_TF1 != INVALID_HANDLE) IndicatorRelease(handleSlowMA_TF1);
if(handleFastMA_TF2 != INVALID_HANDLE) IndicatorRelease(handleFastMA_TF2);
if(handleSlowMA_TF2 != INVALID_HANDLE) IndicatorRelease(handleSlowMA_TF2);
if(handleFastMA_TF3 != INVALID_HANDLE) IndicatorRelease(handleFastMA_TF3);
if(handleSlowMA_TF3 != INVALID_HANDLE) IndicatorRelease(handleSlowMA_TF3);
if(handleRSI_TF1 != INVALID_HANDLE) IndicatorRelease(handleRSI_TF1);
if(handleRSI_TF2 != INVALID_HANDLE) IndicatorRelease(handleRSI_TF2);
if(handleRSI_TF3 != INVALID_HANDLE) IndicatorRelease(handleRSI_TF3);
if(handleBB_TF1 != INVALID_HANDLE) IndicatorRelease(handleBB_TF1);
if(handleBB_TF2 != INVALID_HANDLE) IndicatorRelease(handleBB_TF2);
if(handleBB_TF3 != INVALID_HANDLE) IndicatorRelease(handleBB_TF3);
if(handleMACD_TF1 != INVALID_HANDLE) IndicatorRelease(handleMACD_TF1);
if(handleMACD_TF2 != INVALID_HANDLE) IndicatorRelease(handleMACD_TF2);
if(handleMACD_TF3 != INVALID_HANDLE) IndicatorRelease(handleMACD_TF3);
if(handleATR != INVALID_HANDLE) IndicatorRelease(handleATR);
}
//+------------------------------------------------------------------+