diff --git a/README.md b/README.md new file mode 100644 index 0000000..69c1ab2 --- /dev/null +++ b/README.md @@ -0,0 +1,40 @@ +# Profitable Expert Advisors Collection + +## Project Overview +This repository contains a collection of profitable MetaTrader 5 (MT5) Expert Advisors, each implementing different trading strategies. These EAs have been developed and tested for optimal performance in various market conditions. + +## Available Expert Advisors + +### 1. RSI Divergence Rebound +A strategy that combines RSI (Relative Strength Index) divergence detection with price action analysis to identify potential reversal points in the market. + +**Key Features:** +- RSI divergence patterns detection (bullish and bearish) +- Price rebound confirmation +- Risk management through stop loss and take profit levels + +**Performance Report:** + + +**Balance Sheet:** +![Balance Sheet](RSIDivergenceRebound/test-balance.jpg) + +## Technical Details +Each EA is implemented in MQL5 and includes: +- Custom strategy implementation +- Entry/exit logic +- Risk management parameters +- Position sizing rules + +## Requirements +- MetaTrader 5 platform +- MQL5 programming language support +- Sufficient historical data for backtesting + +## Installation +1. Copy the desired EA file to your MT5 Experts folder +2. Compile the EA in MetaEditor +3. Attach the EA to a chart with appropriate settings + +## Disclaimer +These Expert Advisors are for educational and research purposes only. Past performance does not guarantee future results. Always test thoroughly before using in live trading. diff --git a/RSIDivergenceRebound/ReportTester-51278111.html b/RSIDivergenceRebound/ReportTester-51278111.html new file mode 100644 index 0000000..273a30d Binary files /dev/null and b/RSIDivergenceRebound/ReportTester-51278111.html differ diff --git a/RSIDivergenceRebound/main.mq5 b/RSIDivergenceRebound/main.mq5 new file mode 100644 index 0000000..741bd8d --- /dev/null +++ b/RSIDivergenceRebound/main.mq5 @@ -0,0 +1,441 @@ +//+------------------------------------------------------------------+ +//| RSIDivergenceRebound.mq5 | +//| Copyright 2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2024, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +#property strict + +// Input Parameters +input int RSI_Period = 14; // RSI Period +input int RSI_Overbought = 70; // RSI Overbought Level +input int RSI_Oversold = 30; // RSI Oversold Level +input double BaseLotSize = 0.01; // Base Lot Size +input int ATR_Period = 14; // ATR Period +input double ATR_SL_Multiplier = 3.0; // ATR Stop Loss Multiplier +input double ATR_TP_Multiplier = 10.0; // ATR Take Profit Multiplier +input int MaxSpread = 50; // Maximum Spread in Points +input int DivergenceLookback = 9; // Number of bars to look back for divergence +input int MinTradeInterval = 30; // Minimum minutes between trades +input double MaxRiskPercent = 2.0; // Maximum risk per trade (% of balance) +input double MaxDrawdownPercent = 10.0; // Maximum drawdown before reset (% of balance) +input int MaxConsecutiveLosses = 3; // Maximum consecutive losses before reset +input double MaxLotSize = 0.1; // Maximum allowed lot size +input bool UseRegularDivergence = true; // Use regular divergence for reversals +input bool UseHiddenDivergence = true; // Use hidden divergence for continuations +input int RSI_ConfirmationBars = 19; // Number of bars to confirm RSI pattern + +// Global Variables +int rsiHandle; // RSI indicator handle +int atrHandle; // ATR indicator handle +datetime lastTradeTime = 0; // Last trade time +datetime lastDebugTime = 0; // Last debug message time +double currentLotSize = 0; // Current lot size +bool lastTradeWasWin = false; // Flag for last trade result +int consecutiveLosses = 0; // Count of consecutive losses +double initialBalance = 0; // Initial account balance +double maxBalance = 0; // Maximum balance reached + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() +{ + // Initialize indicators + rsiHandle = iRSI(_Symbol, PERIOD_H1, RSI_Period, PRICE_CLOSE); + atrHandle = iATR(_Symbol, PERIOD_H1, ATR_Period); + + if(rsiHandle == INVALID_HANDLE || atrHandle == INVALID_HANDLE) + { + Print("Error creating indicators"); + return(INIT_FAILED); + } + + // Initialize variables + currentLotSize = BaseLotSize; + lastTradeWasWin = false; + lastTradeTime = 0; + consecutiveLosses = 0; + initialBalance = AccountInfoDouble(ACCOUNT_BALANCE); + maxBalance = initialBalance; + + Print("RSI Divergence Rebound Strategy Initialized"); + Print("Base Lot Size: ", BaseLotSize); + Print("RSI Period: ", RSI_Period, ", ATR Period: ", ATR_Period); + Print("Max Risk per Trade: ", MaxRiskPercent, "%"); + Print("Max Drawdown: ", MaxDrawdownPercent, "%"); + + return(INIT_SUCCEEDED); +} + +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) +{ + // Release indicator handles + IndicatorRelease(rsiHandle); + IndicatorRelease(atrHandle); +} + +//+------------------------------------------------------------------+ +//| Get ATR value for stop loss and take profit calculations | +//+------------------------------------------------------------------+ +double GetATRValue() +{ + double atrBuffer[]; + ArraySetAsSeries(atrBuffer, true); + + if(CopyBuffer(atrHandle, 0, 0, 1, atrBuffer) != 1) + { + Print("Error copying ATR buffer"); + return 0; + } + + return atrBuffer[0]; +} + +//+------------------------------------------------------------------+ +//| Check for RSI divergence patterns | +//+------------------------------------------------------------------+ +int CheckRSIDivergence() +{ + double rsiBuffer[]; + double highBuffer[]; + double lowBuffer[]; + + ArraySetAsSeries(rsiBuffer, true); + ArraySetAsSeries(highBuffer, true); + ArraySetAsSeries(lowBuffer, true); + + if(CopyBuffer(rsiHandle, 0, 0, DivergenceLookback + 1, rsiBuffer) != DivergenceLookback + 1 || + CopyHigh(_Symbol, PERIOD_H1, 0, DivergenceLookback + 1, highBuffer) != DivergenceLookback + 1 || + CopyLow(_Symbol, PERIOD_H1, 0, DivergenceLookback + 1, lowBuffer) != DivergenceLookback + 1) + { + Print("Error copying data for divergence check"); + return 0; + } + + // Check for regular bullish divergence (price makes lower low, RSI makes higher low) + if(UseRegularDivergence) + { + for(int i = 1; i < DivergenceLookback; i++) + { + if(lowBuffer[i] < lowBuffer[i+1] && rsiBuffer[i] > rsiBuffer[i+1] && + rsiBuffer[i] > RSI_Oversold && rsiBuffer[i] < RSI_Overbought) + { + // Confirm RSI is making higher lows + if(rsiBuffer[0] > rsiBuffer[1] && rsiBuffer[1] > rsiBuffer[2]) + { + Print("Regular bullish divergence detected"); + return 1; // Bullish signal + } + } + } + + // Check for regular bearish divergence (price makes higher high, RSI makes lower high) + for(int i = 1; i < DivergenceLookback; i++) + { + if(highBuffer[i] > highBuffer[i+1] && rsiBuffer[i] < rsiBuffer[i+1] && + rsiBuffer[i] > RSI_Oversold && rsiBuffer[i] < RSI_Overbought) + { + // Confirm RSI is making lower highs + if(rsiBuffer[0] < rsiBuffer[1] && rsiBuffer[1] < rsiBuffer[2]) + { + Print("Regular bearish divergence detected"); + return -1; // Bearish signal + } + } + } + } + + // Check for hidden bullish divergence (price makes higher low, RSI makes lower low) + if(UseHiddenDivergence) + { + for(int i = 1; i < DivergenceLookback; i++) + { + if(lowBuffer[i] > lowBuffer[i+1] && rsiBuffer[i] < rsiBuffer[i+1] && + rsiBuffer[i] > RSI_Oversold && rsiBuffer[i] < RSI_Overbought) + { + // Confirm RSI is making higher lows + if(rsiBuffer[0] > rsiBuffer[1] && rsiBuffer[1] > rsiBuffer[2]) + { + Print("Hidden bullish divergence detected"); + return 1; // Bullish signal + } + } + } + + // Check for hidden bearish divergence (price makes lower high, RSI makes higher high) + for(int i = 1; i < DivergenceLookback; i++) + { + if(highBuffer[i] < highBuffer[i+1] && rsiBuffer[i] > rsiBuffer[i+1] && + rsiBuffer[i] > RSI_Oversold && rsiBuffer[i] < RSI_Overbought) + { + // Confirm RSI is making lower highs + if(rsiBuffer[0] < rsiBuffer[1] && rsiBuffer[1] < rsiBuffer[2]) + { + Print("Hidden bearish divergence detected"); + return -1; // Bearish signal + } + } + } + } + + return 0; // No signal +} + +//+------------------------------------------------------------------+ +//| Check if we can open a new position | +//+------------------------------------------------------------------+ +bool CanOpenPosition() +{ + // Check spread + long currentSpread = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD); + if(currentSpread > MaxSpread) + { + Print("Spread too high: ", currentSpread); + return false; + } + + // Check minimum time between trades + datetime currentTime = TimeCurrent(); + if(currentTime - lastTradeTime < MinTradeInterval * 60) + { + Print("Minimum time between trades not reached - Time since last trade: ", + (currentTime - lastTradeTime) / 60, " minutes"); + return false; + } + + // Check for existing positions + int total = PositionsTotal(); + for(int i = 0; i < total; i++) + { + ulong ticket = PositionGetTicket(i); + if(PositionSelectByTicket(ticket)) + { + if(PositionGetString(POSITION_SYMBOL) == _Symbol) + { + Print("Position already exists - Ticket: ", ticket); + return false; + } + } + } + + return true; +} + +//+------------------------------------------------------------------+ +//| Open new position | +//+------------------------------------------------------------------+ +bool OpenPosition(ENUM_POSITION_TYPE posType) +{ + // Validate lot size before attempting to open position + double maxLotSize = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX); + double minLotSize = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN); + + if(currentLotSize > maxLotSize || currentLotSize < minLotSize) + { + currentLotSize = BaseLotSize; + Print("Lot size out of limits - Resetting to base: ", currentLotSize); + } + + // Calculate required margin for the position + double marginRequired = SymbolInfoDouble(_Symbol, SYMBOL_MARGIN_INITIAL) * currentLotSize; + double freeMargin = AccountInfoDouble(ACCOUNT_MARGIN_FREE); + + // If not enough margin, reduce lot size + while(marginRequired > freeMargin && currentLotSize > minLotSize) + { + currentLotSize = NormalizeDouble(currentLotSize * 0.5, 2); + marginRequired = SymbolInfoDouble(_Symbol, SYMBOL_MARGIN_INITIAL) * currentLotSize; + Print("Insufficient margin - Reducing lot size to: ", currentLotSize); + } + + // If still not enough margin, reset to base lot size + if(marginRequired > freeMargin) + { + currentLotSize = BaseLotSize; + marginRequired = SymbolInfoDouble(_Symbol, SYMBOL_MARGIN_INITIAL) * currentLotSize; + Print("Still insufficient margin - Resetting to base lot size: ", currentLotSize); + } + + // Get current ATR value + double atrValue = GetATRValue(); + if(atrValue == 0) + { + Print("Error getting ATR value"); + return false; + } + + double price = (posType == POSITION_TYPE_BUY) ? SymbolInfoDouble(_Symbol, SYMBOL_ASK) + : SymbolInfoDouble(_Symbol, SYMBOL_BID); + + double sl = (posType == POSITION_TYPE_BUY) + ? price - (atrValue * ATR_SL_Multiplier) + : price + (atrValue * ATR_SL_Multiplier); + + double tp = (posType == POSITION_TYPE_BUY) + ? price + (atrValue * ATR_TP_Multiplier) + : price - (atrValue * ATR_TP_Multiplier); + + MqlTradeRequest request = {}; + MqlTradeResult result = {}; + + request.action = TRADE_ACTION_DEAL; + request.symbol = _Symbol; + request.volume = currentLotSize; + request.type = (posType == POSITION_TYPE_BUY) ? ORDER_TYPE_BUY : ORDER_TYPE_SELL; + request.price = price; + request.sl = sl; + request.tp = tp; + request.deviation = 10; + request.magic = 123456; + + // Set filling mode for XAUUSD + request.type_filling = ORDER_FILLING_FOK; // Fill or Kill + + // If FOK fails, try IOC + if(!OrderSend(request, result)) + { + request.type_filling = ORDER_FILLING_IOC; // Immediate or Cancel + if(!OrderSend(request, result)) + { + Print("Failed to open position. Error: ", GetLastError()); + return false; + } + } + + if(result.retcode != TRADE_RETCODE_DONE) + { + Print("Order failed. Return code: ", result.retcode); + return false; + } + + lastTradeTime = TimeCurrent(); + Print("Position opened successfully - Lot size: ", currentLotSize, + ", ATR: ", atrValue, + ", SL: ", sl, + ", TP: ", tp); + return true; +} + +//+------------------------------------------------------------------+ +//| Check if we need to reset due to drawdown or consecutive losses | +//+------------------------------------------------------------------+ +bool NeedToReset() +{ + double currentBalance = AccountInfoDouble(ACCOUNT_BALANCE); + double currentEquity = AccountInfoDouble(ACCOUNT_EQUITY); + + // Update maximum balance + if(currentBalance > maxBalance) + maxBalance = currentBalance; + + // Calculate current drawdown + double drawdownPercent = ((maxBalance - currentEquity) / maxBalance) * 100.0; + + // Check if we've hit maximum drawdown + if(drawdownPercent >= MaxDrawdownPercent) + { + Print("Maximum drawdown reached - Drawdown: ", drawdownPercent, "%"); + return true; + } + + // Check if we've hit maximum consecutive losses + if(consecutiveLosses >= MaxConsecutiveLosses) + { + Print("Maximum consecutive losses reached - Losses: ", consecutiveLosses); + return true; + } + + return false; +} + +//+------------------------------------------------------------------+ +//| Check for closed positions and update lot size | +//+------------------------------------------------------------------+ +void CheckClosedPositions() +{ + static int lastTotal = 0; + int currentTotal = PositionsTotal(); + + // If we have fewer positions than before, a position was closed + if(currentTotal < lastTotal) + { + // Check history for the last closed position + HistorySelect(TimeCurrent() - 3600, TimeCurrent()); + int historyTotal = HistoryDealsTotal(); + + if(historyTotal > 0) + { + ulong dealTicket = HistoryDealGetTicket(historyTotal - 1); + if(dealTicket > 0) + { + double dealProfit = HistoryDealGetDouble(dealTicket, DEAL_PROFIT); + bool isWin = (dealProfit > 0); + + Print("Position closed - Profit: ", dealProfit, + ", Win: ", isWin ? "Yes" : "No"); + + if(isWin) + { + lastTradeWasWin = true; + consecutiveLosses = 0; + } + else + { + lastTradeWasWin = false; + consecutiveLosses++; + + // Check if we need to reset due to drawdown or consecutive losses + if(NeedToReset()) + { + consecutiveLosses = 0; + Print("Reset triggered"); + } + } + } + } + } + + lastTotal = currentTotal; +} + +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() +{ + datetime currentTime = TimeCurrent(); + + // Print debug info every minute + if(currentTime - lastDebugTime >= 60) + { + lastDebugTime = currentTime; + Print("Current lot size: ", currentLotSize, + ", Last trade was win: ", lastTradeWasWin ? "Yes" : "No"); + } + + // Check for closed positions and update lot size + CheckClosedPositions(); + + // Check for entry signals + if(CanOpenPosition()) + { + int signal = CheckRSIDivergence(); + + if(signal == 1) // Bullish signal + { + Print("Opening buy position with lot size: ", currentLotSize); + OpenPosition(POSITION_TYPE_BUY); + } + else if(signal == -1) // Bearish signal + { + Print("Opening sell position with lot size: ", currentLotSize); + OpenPosition(POSITION_TYPE_SELL); + } + } +} diff --git a/RSIDivergenceRebound/test-balance.jpg b/RSIDivergenceRebound/test-balance.jpg new file mode 100644 index 0000000..91fe42c Binary files /dev/null and b/RSIDivergenceRebound/test-balance.jpg differ diff --git a/fast_commit.ps1 b/fast_commit.ps1 new file mode 100644 index 0000000..58617b2 --- /dev/null +++ b/fast_commit.ps1 @@ -0,0 +1,102 @@ +# Function to initialize repository with master and develop branches +function Initialize-GitBranches { + $branches = git branch | ForEach-Object { $_.TrimStart('* ') } | Where-Object { $_ } + + if ($branches.Count -eq 0) { + Write-Host "`nNo branches found. Initializing repository with master and develop branches..." + + # Create and switch to master branch + git checkout -b master + + # Create initial commit if needed + if (-not (git log -n 1 2>$null)) { + Write-Host "Creating initial commit..." + git commit --allow-empty -m "Initial commit" + } + + # Create and push develop branch + git checkout -b develop + + # Push both branches to remote + git push -u origin master + git push -u origin develop + + Write-Host "Repository initialized with master and develop branches" + return $true + } + return $false +} + +# Fetch latest changes from remote +Write-Host "Fetching latest changes from remote..." +git fetch +Write-Host "Fetch completed`n" + +# Check and initialize branches if needed +$initialized = Initialize-GitBranches +if ($initialized) { + Write-Host "`nPlease run the script again to commit your changes." + exit +} + +# Function to select branch +function Select-GitBranch { + Write-Host "Available branches (local and remote):" + $branches = git branch -a | ForEach-Object { $_.TrimStart('* ').TrimStart('remotes/origin/') } | Where-Object { $_ -and $_ -ne 'HEAD' } | Sort-Object -Unique + $branches | ForEach-Object { Write-Host " $_" } + + do { + $selection = Read-Host "Enter branch name" + $branch = $branches | Where-Object { $_ -eq $selection } + if (-not $branch) { + Write-Host "Invalid branch name. Please try again." + } + } until ($branch) + + Write-Host "Selected branch: $branch" + return $branch +} + +# Get current branch +$current_branch = git branch --show-current +Write-Host "Current branch: $current_branch" + +# Ask for commit message +do { + $commit_message = Read-Host "Enter commit message" +} until ($commit_message) + +# Show status and ask for confirmation +git status +$confirm = Read-Host "`nCommit these changes? (y/n)" + +if ($confirm -ne "y") { + Write-Host "Commit cancelled" + exit +} + +# Select target branch +Write-Host "`nSelect target branch:" +$branch = Select-GitBranch + +# Commit and push +git add . +git commit -m $commit_message + +# If current branch is different from target, ask to switch +if ($branch -ne $current_branch) { + $switch_confirm = Read-Host "`nSwitch to $branch and merge changes? (y/n)" + + if ($switch_confirm -eq "y") { + git checkout $branch + git merge $current_branch + } +} + +# Ask to push +$push_confirm = Read-Host "`nPush changes to remote? (y/n)" + +if ($push_confirm -eq "y") { + git push origin $branch + Write-Host "Changes pushed successfully" +} \ No newline at end of file