diff --git a/frontline/MQL5/DarvasBoxXAUUSD/main.mq5 b/frontline/MQL5/DarvasBoxXAUUSD/main.mq5 index b105d1f..6da93f9 100644 --- a/frontline/MQL5/DarvasBoxXAUUSD/main.mq5 +++ b/frontline/MQL5/DarvasBoxXAUUSD/main.mq5 @@ -11,6 +11,7 @@ #include #include #include +#include "../_united/MagicNumberHelpers.mqh" // Input parameters input int BoxPeriod = 165; // Period for Darvas Box calculation @@ -33,6 +34,9 @@ input double TrendThreshold = 4.94; // Trend strength threshold input int VolumeMA_Period = 110; // Period for Volume MA input double VolumeThresholdMultiplier = 1.5; // Volume spike threshold +// Magic Number +input int MagicNumber = 135790; // Magic Number for Trades + // Global variables double boxHigh = 0; double boxLow = 0; @@ -42,7 +46,6 @@ string boxName = "DarvasBox_"; double minStopLevel = 0; double point = 0; CTrade trade; -ulong magicNumber = 135790; // Indicator handles int maHandle; @@ -77,7 +80,7 @@ int OnInit() trade.SetDeviationInPoints(10); trade.SetTypeFilling(ORDER_FILLING_IOC); trade.SetAsyncMode(false); - trade.SetExpertMagicNumber(magicNumber); + trade.SetExpertMagicNumber(MagicNumber); if(EnableLogging) { @@ -343,7 +346,7 @@ void OnTick() Print("Breakout Signal Detected - Price above box high"); // Buy signal - if(PositionsTotal() == 0) // No existing positions + if(!PositionExistsByMagic(_Symbol, MagicNumber)) // No existing positions with our magic number { double sl = currentPrice - StopLoss * _Point; double tp = currentPrice + TakeProfit * _Point; @@ -364,7 +367,7 @@ void OnTick() Print("Breakdown Signal Detected - Price below box low"); // Sell signal - if(PositionsTotal() == 0) // No existing positions + if(!PositionExistsByMagic(_Symbol, MagicNumber)) // No existing positions with our magic number { double sl = currentPrice + StopLoss * _Point; double tp = currentPrice - TakeProfit * _Point; diff --git a/frontline/MQL5/EMASlopeDistanceCocktailXAUUSD/main.mq5 b/frontline/MQL5/EMASlopeDistanceCocktailXAUUSD/main.mq5 index e426b5e..bd4661d 100644 --- a/frontline/MQL5/EMASlopeDistanceCocktailXAUUSD/main.mq5 +++ b/frontline/MQL5/EMASlopeDistanceCocktailXAUUSD/main.mq5 @@ -7,6 +7,7 @@ #property link "https://www.mql5.com" #property version "1.00" #include +#include "../_united/MagicNumberHelpers.mqh" //--- Eingabeparameter (Input Parameters) - Optimized Profitable Parameters input int EMA_Periode = 46; // EMA Periode input double PreisSchwelle = 600.0; // Preisbewegung Schwelle in Pips @@ -127,7 +128,7 @@ void OnTick() Print("Differenz Close-EMA: ", aktueller_close - ema_aktuell); Print("Preis-Trigger: ", preis_trigger_aktiv, " Steigungs-Trigger: ", steigung_trigger_aktiv); Print("Überwachung aktiv: ", überwachung_aktiv); - Print("Position offen: ", PositionSelect(_Symbol)); + Print("Position offen: ", PositionExistsByMagic(_Symbol, MagicNumber)); Print("Trades im aktuellen Crossover: ", trades_in_current_crossover, "/", MaxTradesPerCrossover); Print("=================="); } @@ -289,7 +290,7 @@ void PrüfeTrigger() return; } - if(bullish_signal && !PositionSelect(_Symbol)) + if(bullish_signal && !PositionExistsByMagic(_Symbol, MagicNumber)) { Print("TRACE: Versuche KAUF-Trade zu platzieren (Trade #", trades_in_current_crossover + 1, ")"); if(PlatziereTrade(ORDER_TYPE_BUY)) @@ -297,7 +298,7 @@ void PrüfeTrigger() trades_in_current_crossover++; } } - else if(bearish_signal && !PositionSelect(_Symbol)) + else if(bearish_signal && !PositionExistsByMagic(_Symbol, MagicNumber)) { Print("TRACE: Versuche VERKAUF-Trade zu platzieren (Trade #", trades_in_current_crossover + 1, ")"); if(PlatziereTrade(ORDER_TYPE_SELL)) @@ -305,7 +306,7 @@ void PrüfeTrigger() trades_in_current_crossover++; } } - else if(PositionSelect(_Symbol)) + else if(PositionExistsByMagic(_Symbol, MagicNumber)) { Print("TRACE: Position bereits offen - kein neuer Trade"); } @@ -361,7 +362,7 @@ bool PlatziereTrade(ENUM_ORDER_TYPE order_type) //+------------------------------------------------------------------+ void VerwalteTrades() { - if(!PositionSelect(_Symbol)) + if(!PositionSelectByMagic(_Symbol, MagicNumber)) return; double position_profit = PositionGetDouble(POSITION_PROFIT); @@ -417,7 +418,7 @@ void VerwalteTrades() } //--- Profit-Prüfung nach X Bars (Profit check after X bars) - if(CloseUnprofitableTrades && trade_open_time != 0 && PositionSelect(_Symbol)) + if(CloseUnprofitableTrades && trade_open_time != 0 && PositionExistsByMagic(_Symbol, MagicNumber)) { Print("TRACE: Profit-Prüfung aktiviert - CloseUnprofitableTrades: ", CloseUnprofitableTrades); PrüfeProfitNachBars(); @@ -433,7 +434,7 @@ void VerwalteTrades() //+------------------------------------------------------------------+ void PrüfeProfitNachBars() { - if(!PositionSelect(_Symbol)) + if(!PositionSelectByMagic(_Symbol, MagicNumber)) { return; // Keine Position offen } @@ -479,7 +480,7 @@ void ÄndereStopLoss(double new_stop_loss) { Print("TRACE: Versuche Stop Loss zu ändern auf: ", new_stop_loss); - bool success = trade.PositionModify(_Symbol, new_stop_loss, PositionGetDouble(POSITION_TP)); + bool success = ModifyPositionByMagic(trade, _Symbol, MagicNumber, new_stop_loss, PositionGetDouble(POSITION_TP)); if(success) { @@ -499,7 +500,7 @@ void SchließePosition(string reason = "Unbekannt") { Print("TRACE: Versuche Position zu schließen - Grund: ", reason); - bool success = trade.PositionClose(_Symbol); + bool success = ClosePositionByMagic(trade, _Symbol, MagicNumber); if(success) { diff --git a/frontline/MQL5/IMPROVEMENT.md b/frontline/MQL5/IMPROVEMENT.md new file mode 100644 index 0000000..d56b9c1 --- /dev/null +++ b/frontline/MQL5/IMPROVEMENT.md @@ -0,0 +1,82 @@ +# MQL5 EA Improvements - Magic Number Isolation + +## Problem +When multiple EAs run together on the same symbol, they interfere with each other because magic numbers are not properly checked in all position-related functions. + +## Solution +1. Created `MagicNumberHelpers.mqh` with magic-aware helper functions +2. Updated EAs to use these helper functions +3. Created `_united/main.mq5` - a unified EA that runs multiple strategies together + +## Fixed Functions + +### Helper Functions (MagicNumberHelpers.mqh) +- `PositionSelectByMagic()` - Select position by symbol AND magic number +- `PositionSelectByTicketAndMagic()` - Verify ticket has correct magic number +- `PositionExistsByMagic()` - Check if position exists with magic number +- `GetPositionTicketByMagic()` - Get ticket by symbol and magic number +- `ClosePositionByMagic()` - Close position with magic number verification +- `ModifyPositionByMagic()` - Modify position with magic number verification +- `GetPositionProfitByMagic()` - Get profit with magic number check +- `GetPositionTypeByMagic()` - Get position type with magic number check +- `CountPositionsByMagic()` - Count positions with specific magic number + +## Fixed EAs + +### RSIScalpingXAUUSD +- ✅ Fixed `CheckExistingPosition()` to use `PositionSelectByTicketAndMagic()` +- ✅ Fixed `ClosePosition()` to verify magic number before closing +- ✅ Fixed entry signal check to use `PositionExistsByMagic()` + +### MeanReversionXAUUSD +- ✅ Fixed all `PositionSelect(_Symbol)` calls to use `PositionSelectByMagic()` +- ✅ Fixed `SchließePosition()` to use `ClosePositionByMagic()` +- ✅ Fixed `ÄndereStopLoss()` to use `ModifyPositionByMagic()` +- ✅ Fixed all position existence checks to use `PositionExistsByMagic()` + +## United EA + +The `_united/main.mq5` EA allows running multiple strategies together: +- Each strategy has its own unique magic number +- Strategies operate independently without interference +- Can enable/disable individual strategies via input parameters +- Currently implements: + - RSI Scalping Strategy + - Mean Reversion Strategy + - Framework for additional strategies (DarvasBox, RSICrossOver, RSIMidPoint) + +## Usage + +### For Individual EAs +Simply include the helper file: +```mql5 +#include "../_united/MagicNumberHelpers.mqh" +``` + +Then replace: +- `PositionSelect(_Symbol)` → `PositionSelectByMagic(_Symbol, MagicNumber)` +- `PositionSelectByTicket(ticket)` → `PositionSelectByTicketAndMagic(ticket, MagicNumber)` +- `trade.PositionClose(_Symbol)` → `ClosePositionByMagic(trade, _Symbol, MagicNumber)` +- `trade.PositionModify(_Symbol, ...)` → `ModifyPositionByMagic(trade, _Symbol, MagicNumber, ...)` + +### For United EA +1. Set unique magic numbers for each strategy +2. Enable/disable strategies via input parameters +3. Configure strategy-specific parameters +4. Run on chart - all enabled strategies will operate independently + +## Remaining EAs to Fix + +The following EAs should be updated similarly: +- DarvasBoxXAUUSD +- RSICrossOverReversalXAUUSD +- RSIMidPointHijackXAUUSD +- EMASlopeDistanceCocktailXAUUSD +- All RSIScalping variants (APPL, BTCUSD, MSFT, NVDA, TSLA) + +## Best Practices + +1. **Always use magic-aware functions** when checking/modifying positions +2. **Set unique magic numbers** for each EA instance +3. **Verify magic number** before any position operation +4. **Use United EA** when running multiple strategies on same symbol diff --git a/frontline/MQL5/MeanReversionXAUUSD/main.mq5 b/frontline/MQL5/MeanReversionXAUUSD/main.mq5 index 0db4acd..8a0349e 100644 --- a/frontline/MQL5/MeanReversionXAUUSD/main.mq5 +++ b/frontline/MQL5/MeanReversionXAUUSD/main.mq5 @@ -7,6 +7,7 @@ #property copyright "Copyright 2025, MetaQuotes Ltd." #property version "1.00" #include +#include "../_united/MagicNumberHelpers.mqh" //--- Eingabeparameter (Input Parameters) - Optimized Profitable Parameters input int EMA_Periode = 46; // EMA Periode input double PreisSchwelle = 600.0; // Preisbewegung Schwelle in Pips @@ -127,7 +128,7 @@ void OnTick() Print("Differenz Close-EMA: ", aktueller_close - ema_aktuell); Print("Preis-Trigger: ", preis_trigger_aktiv, " Steigungs-Trigger: ", steigung_trigger_aktiv); Print("Überwachung aktiv: ", überwachung_aktiv); - Print("Position offen: ", PositionSelect(_Symbol)); + Print("Position offen: ", PositionExistsByMagic(_Symbol, MagicNumber)); Print("Trades im aktuellen Crossover: ", trades_in_current_crossover, "/", MaxTradesPerCrossover); Print("=================="); } @@ -289,7 +290,7 @@ void PrüfeTrigger() return; } - if(bullish_signal && !PositionSelect(_Symbol)) + if(bullish_signal && !PositionExistsByMagic(_Symbol, MagicNumber)) { Print("TRACE: Versuche KAUF-Trade zu platzieren (Trade #", trades_in_current_crossover + 1, ")"); if(PlatziereTrade(ORDER_TYPE_BUY)) @@ -297,7 +298,7 @@ void PrüfeTrigger() trades_in_current_crossover++; } } - else if(bearish_signal && !PositionSelect(_Symbol)) + else if(bearish_signal && !PositionExistsByMagic(_Symbol, MagicNumber)) { Print("TRACE: Versuche VERKAUF-Trade zu platzieren (Trade #", trades_in_current_crossover + 1, ")"); if(PlatziereTrade(ORDER_TYPE_SELL)) @@ -305,7 +306,7 @@ void PrüfeTrigger() trades_in_current_crossover++; } } - else if(PositionSelect(_Symbol)) + else if(PositionExistsByMagic(_Symbol, MagicNumber)) { Print("TRACE: Position bereits offen - kein neuer Trade"); } @@ -361,7 +362,7 @@ bool PlatziereTrade(ENUM_ORDER_TYPE order_type) //+------------------------------------------------------------------+ void VerwalteTrades() { - if(!PositionSelect(_Symbol)) + if(!PositionSelectByMagic(_Symbol, MagicNumber)) return; double position_profit = PositionGetDouble(POSITION_PROFIT); @@ -417,7 +418,7 @@ void VerwalteTrades() } //--- Profit-Prüfung nach X Bars (Profit check after X bars) - if(CloseUnprofitableTrades && trade_open_time != 0 && PositionSelect(_Symbol)) + if(CloseUnprofitableTrades && trade_open_time != 0 && PositionExistsByMagic(_Symbol, MagicNumber)) { Print("TRACE: Profit-Prüfung aktiviert - CloseUnprofitableTrades: ", CloseUnprofitableTrades); PrüfeProfitNachBars(); @@ -433,7 +434,7 @@ void VerwalteTrades() //+------------------------------------------------------------------+ void PrüfeProfitNachBars() { - if(!PositionSelect(_Symbol)) + if(!PositionSelectByMagic(_Symbol, MagicNumber)) { return; // Keine Position offen } @@ -479,7 +480,7 @@ void ÄndereStopLoss(double new_stop_loss) { Print("TRACE: Versuche Stop Loss zu ändern auf: ", new_stop_loss); - bool success = trade.PositionModify(_Symbol, new_stop_loss, PositionGetDouble(POSITION_TP)); + bool success = ModifyPositionByMagic(trade, _Symbol, MagicNumber, new_stop_loss, PositionGetDouble(POSITION_TP)); if(success) { @@ -499,7 +500,7 @@ void SchließePosition(string reason = "Unbekannt") { Print("TRACE: Versuche Position zu schließen - Grund: ", reason); - bool success = trade.PositionClose(_Symbol); + bool success = ClosePositionByMagic(trade, _Symbol, MagicNumber); if(success) { diff --git a/frontline/MQL5/RSICrossOverReversalXAUUSD/main.mq5 b/frontline/MQL5/RSICrossOverReversalXAUUSD/main.mq5 index 5c004da..c4c7508 100644 --- a/frontline/MQL5/RSICrossOverReversalXAUUSD/main.mq5 +++ b/frontline/MQL5/RSICrossOverReversalXAUUSD/main.mq5 @@ -1,5 +1,6 @@ // Input Parameters #include +#include "../_united/MagicNumberHelpers.mqh" input group "Trade Management" input int MagicNumber = 7; @@ -125,7 +126,7 @@ void OnTick() { // Ensure there is at least one position - bool hasPosition = (PositionsTotal() > 0); + bool hasPosition = PositionExistsByMagic(_Symbol, MagicNumber); @@ -157,7 +158,7 @@ void OnTick() { bool isBuyPosition = false; bool isSellPosition = false; if (hasPosition) { - if (PositionSelect(_Symbol)) { + if (PositionSelectByMagic(_Symbol, MagicNumber)) { int positionType = PositionGetInteger(POSITION_TYPE); if (positionType == POSITION_TYPE_BUY) { isBuyPosition = true; @@ -237,77 +238,56 @@ void OnDeinit(const int reason) { void Close_Position_MN(ulong magicNumber) { - int total = PositionsTotal(); - for(int i = total - 1; i >= 0; i--) - { - ulong ticket = PositionGetTicket(i); - - // Use PositionSelect by symbol instead of ticket - string symbol = PositionGetSymbol(i); - if(PositionSelect(symbol)) - { - if (PositionGetInteger(POSITION_MAGIC) == magicNumber && PositionGetInteger(POSITION_TICKET) == ticket) - { - if(symbol == _Symbol) // Verify the symbol - { - Print("MN " + magicNumber); - trade.PositionClose(ticket); - } - } - } - else - { - int errorCode = GetLastError(); - Print("aaaa PositionSelect failed with error code: ", errorCode); - } - } + // Use helper function to close position by magic number + ClosePositionByMagic(trade, _Symbol, (int)magicNumber); } void ApplyTrailingStop() { Print("Scanning for trailing stop"); - for(int i=PositionsTotal()-1; i>=0; i--) + + // Check if position exists with our magic number + if(!PositionSelectByMagic(_Symbol, MagicNumber)) { - string symbol = PositionGetSymbol(i); - ulong PositionTicket = PositionGetTicket(i); - long trade_type = PositionGetInteger(POSITION_TYPE); + return; // No position with our magic number + } + + ulong PositionTicket = PositionGetInteger(POSITION_TICKET); + long trade_type = PositionGetInteger(POSITION_TYPE); + string symbol = _Symbol; - if(!PositionGetInteger(POSITION_MAGIC) == MagicNumber) { - return; - } - - double POINT = SymbolInfoDouble( symbol, SYMBOL_POINT ); - int DIGIT = (int) SymbolInfoInteger( symbol, SYMBOL_DIGITS ); + double POINT = SymbolInfoDouble(symbol, SYMBOL_POINT); + int DIGIT = (int) SymbolInfoInteger(symbol, SYMBOL_DIGITS); - - if(trade_type == 0) - { - double Bid = NormalizeDouble(SymbolInfoDouble(symbol,SYMBOL_BID),DIGIT); + if(trade_type == POSITION_TYPE_BUY) + { + double Bid = NormalizeDouble(SymbolInfoDouble(symbol, SYMBOL_BID), DIGIT); - if(Bid-PositionGetDouble(POSITION_PRICE_OPEN) > NormalizeDouble(POINT * TrailingStop,DIGIT)) - { - if(PositionGetDouble(POSITION_SL) < NormalizeDouble(Bid - POINT * TrailingStop,DIGIT)) - { - trade.PositionModify(PositionTicket,NormalizeDouble(Bid - POINT * TrailingStop,DIGIT),PositionGetDouble(POSITION_TP)); - } - } - + if(Bid - PositionGetDouble(POSITION_PRICE_OPEN) > NormalizeDouble(POINT * TrailingStop, DIGIT)) + { + if(PositionGetDouble(POSITION_SL) < NormalizeDouble(Bid - POINT * TrailingStop, DIGIT)) + { + ModifyPositionByMagic(trade, symbol, MagicNumber, + NormalizeDouble(Bid - POINT * TrailingStop, DIGIT), + PositionGetDouble(POSITION_TP)); } - - if(trade_type == 1) - { - double Ask = NormalizeDouble(SymbolInfoDouble(symbol,SYMBOL_ASK),DIGIT); + } + } + else if(trade_type == POSITION_TYPE_SELL) + { + double Ask = NormalizeDouble(SymbolInfoDouble(symbol, SYMBOL_ASK), DIGIT); - if((PositionGetDouble(POSITION_PRICE_OPEN) - Ask) > NormalizeDouble( POINT * TrailingStop,DIGIT)) - { - if((PositionGetDouble(POSITION_SL) > NormalizeDouble(Ask + POINT * TrailingStop,DIGIT)) || (PositionGetDouble(POSITION_SL)==0)) - { - trade.PositionModify(PositionTicket,NormalizeDouble(Ask + POINT * TrailingStop,DIGIT),PositionGetDouble(POSITION_TP)); - } - } - + if((PositionGetDouble(POSITION_PRICE_OPEN) - Ask) > NormalizeDouble(POINT * TrailingStop, DIGIT)) + { + if((PositionGetDouble(POSITION_SL) > NormalizeDouble(Ask + POINT * TrailingStop, DIGIT)) || + (PositionGetDouble(POSITION_SL) == 0)) + { + ModifyPositionByMagic(trade, symbol, MagicNumber, + NormalizeDouble(Ask + POINT * TrailingStop, DIGIT), + PositionGetDouble(POSITION_TP)); } - } + } + } } int TimeHour(datetime when=0){ if(when == 0) when = TimeCurrent(); diff --git a/frontline/MQL5/RSIMidPointHijackXAUUSD/main.mq5 b/frontline/MQL5/RSIMidPointHijackXAUUSD/main.mq5 index d0fc04f..161c0bd 100644 --- a/frontline/MQL5/RSIMidPointHijackXAUUSD/main.mq5 +++ b/frontline/MQL5/RSIMidPointHijackXAUUSD/main.mq5 @@ -9,6 +9,7 @@ #include #include +#include "../_united/MagicNumberHelpers.mqh" // Input Parameters input group "General Settings" @@ -158,19 +159,12 @@ bool IsWithinTradingHours(int startHour, int endHour) } //+------------------------------------------------------------------+ -//| Check if position exists for given magic number | +//| Check if position exists for given magic number AND symbol | //+------------------------------------------------------------------+ bool HasPosition(int magic) { - for(int i = PositionsTotal() - 1; i >= 0; i--) - { - if(positionInfo.SelectByIndex(i)) - { - if(positionInfo.Magic() == magic) - return true; - } - } - return false; + // Use helper function that verifies BOTH symbol AND magic number for THIS EA + return PositionExistsByMagic(_Symbol, magic); } //+------------------------------------------------------------------+ @@ -572,30 +566,39 @@ void CheckExitConditions() //+------------------------------------------------------------------+ void ClosePosition(int magic) { - for(int i = PositionsTotal() - 1; i >= 0; i--) + // Close position using helper that verifies symbol AND magic number for THIS EA + // First check if position exists for this EA on this symbol + if(!PositionExistsByMagic(_Symbol, magic)) { - if(positionInfo.SelectByIndex(i)) + return; // No position for this EA on this symbol + } + + // Get the position ticket for this EA on this symbol + ulong ticket = GetPositionTicketByMagic(_Symbol, magic); + if(ticket == 0) + { + return; // No valid ticket found + } + + // Check if this is RSI Reverse position and update cooldown + if(magic == InpMagicNumberRSIReverse) + { + if(PositionSelectByTicketSymbolAndMagic(ticket, _Symbol, magic)) { - if(positionInfo.Magic() == magic) + datetime time[]; + if(CopyTime(_Symbol, InpTimeframe, 0, 1, time) > 0) { - // Check if this is RSI Reverse position and update cooldown - if(magic == InpMagicNumberRSIReverse) + rsiReverseLastCloseTime = time[0]; + // Only enter cooldown if it's a loss or if cooldown on loss is disabled + double profit = PositionGetDouble(POSITION_PROFIT); + if(!InpRSIReverseCooldownOnLoss || profit < 0) { - datetime time[]; - if(CopyTime(_Symbol, InpTimeframe, 0, 1, time) > 0) - { - rsiReverseLastCloseTime = time[0]; - // Only enter cooldown if it's a loss or if cooldown on loss is disabled - if(!InpRSIReverseCooldownOnLoss || positionInfo.Profit() < 0) - { - rsiReverseInCooldown = true; - } - } + rsiReverseInCooldown = true; } - - trade.PositionClose(positionInfo.Ticket()); - break; } } } + + // Close the position using helper function + ClosePositionByMagic(trade, _Symbol, magic); } diff --git a/frontline/MQL5/RSIScalpingAPPL/main.mq5 b/frontline/MQL5/RSIScalpingAPPL/main.mq5 index 5bc06f4..152fa54 100644 --- a/frontline/MQL5/RSIScalpingAPPL/main.mq5 +++ b/frontline/MQL5/RSIScalpingAPPL/main.mq5 @@ -8,6 +8,7 @@ #property version "1.00" #include +#include "../_united/MagicNumberHelpers.mqh" //--- Input parameters input ENUM_TIMEFRAMES TimeFrame = PERIOD_M10; // Timeframe for Analysis @@ -95,8 +96,8 @@ void OnTick() // Check for existing position CheckExistingPosition(); - // Check for new entry signals - if(!position_open) + // Check for new entry signals - only if no position exists for THIS EA (magic number) on THIS symbol + if(!position_open && !PositionExistsByMagic(_Symbol, MagicNumber)) { CheckEntrySignals(); } @@ -129,8 +130,8 @@ void CheckExistingPosition() return; } - // Check if position still exists - if(!PositionSelectByTicket(position_ticket)) + // Check if position still exists with correct magic number AND symbol for THIS EA + if(!PositionSelectByTicketSymbolAndMagic(position_ticket, _Symbol, MagicNumber)) { position_open = false; position_ticket = 0; @@ -241,13 +242,31 @@ void CheckEntrySignals() //+------------------------------------------------------------------+ void OpenBuyPosition() { + // Verify no position exists for THIS EA (magic number) on THIS symbol before opening + if(PositionExistsByMagic(_Symbol, MagicNumber)) + { + return; // Position already exists for this EA + } + double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); if(trade.Buy(LotSize, _Symbol, ask, 0, 0, "RSI Scalping Buy")) { - position_ticket = trade.ResultOrder(); - position_open = true; - current_position_type = POSITION_TYPE_BUY; + ulong new_ticket = trade.ResultOrder(); + if(new_ticket > 0) + { + // Verify position was opened for THIS EA (magic number) on THIS symbol + if(PositionSelectByTicketSymbolAndMagic(new_ticket, _Symbol, MagicNumber)) + { + position_ticket = new_ticket; + position_open = true; + current_position_type = POSITION_TYPE_BUY; + } + else + { + Print("Error: Position opened but doesn't match EA magic number or symbol"); + } + } } } @@ -256,13 +275,31 @@ void OpenBuyPosition() //+------------------------------------------------------------------+ void OpenSellPosition() { + // Verify no position exists for THIS EA (magic number) on THIS symbol before opening + if(PositionExistsByMagic(_Symbol, MagicNumber)) + { + return; // Position already exists for this EA + } + double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); if(trade.Sell(LotSize, _Symbol, bid, 0, 0, "RSI Scalping Sell")) { - position_ticket = trade.ResultOrder(); - position_open = true; - current_position_type = POSITION_TYPE_SELL; + ulong new_ticket = trade.ResultOrder(); + if(new_ticket > 0) + { + // Verify position was opened for THIS EA (magic number) on THIS symbol + if(PositionSelectByTicketSymbolAndMagic(new_ticket, _Symbol, MagicNumber)) + { + position_ticket = new_ticket; + position_open = true; + current_position_type = POSITION_TYPE_SELL; + } + else + { + Print("Error: Position opened but doesn't match EA magic number or symbol"); + } + } } } @@ -271,11 +308,20 @@ void OpenSellPosition() //+------------------------------------------------------------------+ void ClosePosition() { - if(trade.PositionClose(position_ticket)) + // Close position using helper that verifies symbol AND magic number for THIS EA + if(ClosePositionByMagic(trade, _Symbol, MagicNumber)) { position_open = false; position_ticket = 0; rsi_against_position = false; bars_against_count = 0; } + else + { + // Position doesn't exist or wrong magic number - reset tracking + position_open = false; + position_ticket = 0; + rsi_against_position = false; + bars_against_count = 0; + } } diff --git a/frontline/MQL5/RSIScalpingBTCUSD/main.mq5 b/frontline/MQL5/RSIScalpingBTCUSD/main.mq5 index e51bafd..7866af1 100644 --- a/frontline/MQL5/RSIScalpingBTCUSD/main.mq5 +++ b/frontline/MQL5/RSIScalpingBTCUSD/main.mq5 @@ -8,6 +8,7 @@ #property version "1.00" #include +#include "../_united/MagicNumberHelpers.mqh" //--- Input parameters input ENUM_TIMEFRAMES TimeFrame = PERIOD_H1; // Timeframe for Analysis @@ -95,8 +96,8 @@ void OnTick() // Check for existing position CheckExistingPosition(); - // Check for new entry signals - if(!position_open) + // Check for new entry signals - only if no position exists for THIS EA (magic number) on THIS symbol + if(!position_open && !PositionExistsByMagic(_Symbol, MagicNumber)) { CheckEntrySignals(); } @@ -129,8 +130,8 @@ void CheckExistingPosition() return; } - // Check if position still exists - if(!PositionSelectByTicket(position_ticket)) + // Check if position still exists with correct magic number AND symbol for THIS EA + if(!PositionSelectByTicketSymbolAndMagic(position_ticket, _Symbol, MagicNumber)) { position_open = false; position_ticket = 0; @@ -241,13 +242,31 @@ void CheckEntrySignals() //+------------------------------------------------------------------+ void OpenBuyPosition() { + // Verify no position exists for THIS EA (magic number) on THIS symbol before opening + if(PositionExistsByMagic(_Symbol, MagicNumber)) + { + return; // Position already exists for this EA + } + double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); if(trade.Buy(LotSize, _Symbol, ask, 0, 0, "RSI Scalping Buy")) { - position_ticket = trade.ResultOrder(); - position_open = true; - current_position_type = POSITION_TYPE_BUY; + ulong new_ticket = trade.ResultOrder(); + if(new_ticket > 0) + { + // Verify position was opened for THIS EA (magic number) on THIS symbol + if(PositionSelectByTicketSymbolAndMagic(new_ticket, _Symbol, MagicNumber)) + { + position_ticket = new_ticket; + position_open = true; + current_position_type = POSITION_TYPE_BUY; + } + else + { + Print("Error: Position opened but doesn't match EA magic number or symbol"); + } + } } } @@ -256,13 +275,31 @@ void OpenBuyPosition() //+------------------------------------------------------------------+ void OpenSellPosition() { + // Verify no position exists for THIS EA (magic number) on THIS symbol before opening + if(PositionExistsByMagic(_Symbol, MagicNumber)) + { + return; // Position already exists for this EA + } + double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); if(trade.Sell(LotSize, _Symbol, bid, 0, 0, "RSI Scalping Sell")) { - position_ticket = trade.ResultOrder(); - position_open = true; - current_position_type = POSITION_TYPE_SELL; + ulong new_ticket = trade.ResultOrder(); + if(new_ticket > 0) + { + // Verify position was opened for THIS EA (magic number) on THIS symbol + if(PositionSelectByTicketSymbolAndMagic(new_ticket, _Symbol, MagicNumber)) + { + position_ticket = new_ticket; + position_open = true; + current_position_type = POSITION_TYPE_SELL; + } + else + { + Print("Error: Position opened but doesn't match EA magic number or symbol"); + } + } } } @@ -271,11 +308,20 @@ void OpenSellPosition() //+------------------------------------------------------------------+ void ClosePosition() { - if(trade.PositionClose(position_ticket)) + // Close position using helper that verifies symbol AND magic number for THIS EA + if(ClosePositionByMagic(trade, _Symbol, MagicNumber)) { position_open = false; position_ticket = 0; rsi_against_position = false; bars_against_count = 0; } + else + { + // Position doesn't exist or wrong magic number - reset tracking + position_open = false; + position_ticket = 0; + rsi_against_position = false; + bars_against_count = 0; + } } diff --git a/frontline/MQL5/RSIScalpingMSFT/main.mq5 b/frontline/MQL5/RSIScalpingMSFT/main.mq5 index 72711c3..3627826 100644 --- a/frontline/MQL5/RSIScalpingMSFT/main.mq5 +++ b/frontline/MQL5/RSIScalpingMSFT/main.mq5 @@ -8,6 +8,7 @@ #property version "1.00" #include +#include "../_united/MagicNumberHelpers.mqh" //--- Input parameters input ENUM_TIMEFRAMES TimeFrame = PERIOD_H3; // Timeframe for Analysis @@ -95,8 +96,8 @@ void OnTick() // Check for existing position CheckExistingPosition(); - // Check for new entry signals - if(!position_open) + // Check for new entry signals - only if no position exists for THIS EA (magic number) on THIS symbol + if(!position_open && !PositionExistsByMagic(_Symbol, MagicNumber)) { CheckEntrySignals(); } @@ -129,8 +130,8 @@ void CheckExistingPosition() return; } - // Check if position still exists - if(!PositionSelectByTicket(position_ticket)) + // Check if position still exists with correct magic number AND symbol for THIS EA + if(!PositionSelectByTicketSymbolAndMagic(position_ticket, _Symbol, MagicNumber)) { position_open = false; position_ticket = 0; @@ -241,13 +242,31 @@ void CheckEntrySignals() //+------------------------------------------------------------------+ void OpenBuyPosition() { + // Verify no position exists for THIS EA (magic number) on THIS symbol before opening + if(PositionExistsByMagic(_Symbol, MagicNumber)) + { + return; // Position already exists for this EA + } + double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); if(trade.Buy(LotSize, _Symbol, ask, 0, 0, "RSI Scalping Buy")) { - position_ticket = trade.ResultOrder(); - position_open = true; - current_position_type = POSITION_TYPE_BUY; + ulong new_ticket = trade.ResultOrder(); + if(new_ticket > 0) + { + // Verify position was opened for THIS EA (magic number) on THIS symbol + if(PositionSelectByTicketSymbolAndMagic(new_ticket, _Symbol, MagicNumber)) + { + position_ticket = new_ticket; + position_open = true; + current_position_type = POSITION_TYPE_BUY; + } + else + { + Print("Error: Position opened but doesn't match EA magic number or symbol"); + } + } } } @@ -256,13 +275,31 @@ void OpenBuyPosition() //+------------------------------------------------------------------+ void OpenSellPosition() { + // Verify no position exists for THIS EA (magic number) on THIS symbol before opening + if(PositionExistsByMagic(_Symbol, MagicNumber)) + { + return; // Position already exists for this EA + } + double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); if(trade.Sell(LotSize, _Symbol, bid, 0, 0, "RSI Scalping Sell")) { - position_ticket = trade.ResultOrder(); - position_open = true; - current_position_type = POSITION_TYPE_SELL; + ulong new_ticket = trade.ResultOrder(); + if(new_ticket > 0) + { + // Verify position was opened for THIS EA (magic number) on THIS symbol + if(PositionSelectByTicketSymbolAndMagic(new_ticket, _Symbol, MagicNumber)) + { + position_ticket = new_ticket; + position_open = true; + current_position_type = POSITION_TYPE_SELL; + } + else + { + Print("Error: Position opened but doesn't match EA magic number or symbol"); + } + } } } @@ -271,11 +308,20 @@ void OpenSellPosition() //+------------------------------------------------------------------+ void ClosePosition() { - if(trade.PositionClose(position_ticket)) + // Close position using helper that verifies symbol AND magic number for THIS EA + if(ClosePositionByMagic(trade, _Symbol, MagicNumber)) { position_open = false; position_ticket = 0; rsi_against_position = false; bars_against_count = 0; } + else + { + // Position doesn't exist or wrong magic number - reset tracking + position_open = false; + position_ticket = 0; + rsi_against_position = false; + bars_against_count = 0; + } } diff --git a/frontline/MQL5/RSIScalpingNVDA/main.mq5 b/frontline/MQL5/RSIScalpingNVDA/main.mq5 index 75d1d6d..74b2310 100644 --- a/frontline/MQL5/RSIScalpingNVDA/main.mq5 +++ b/frontline/MQL5/RSIScalpingNVDA/main.mq5 @@ -8,6 +8,7 @@ #property version "1.00" #include +#include "../_united/MagicNumberHelpers.mqh" //--- Input parameters input ENUM_TIMEFRAMES TimeFrame = PERIOD_M15; // Timeframe for Analysis @@ -95,8 +96,8 @@ void OnTick() // Check for existing position CheckExistingPosition(); - // Check for new entry signals - if(!position_open) + // Check for new entry signals - only if no position exists for THIS EA (magic number) on THIS symbol + if(!position_open && !PositionExistsByMagic(_Symbol, MagicNumber)) { CheckEntrySignals(); } @@ -129,8 +130,8 @@ void CheckExistingPosition() return; } - // Check if position still exists - if(!PositionSelectByTicket(position_ticket)) + // Check if position still exists with correct magic number AND symbol for THIS EA + if(!PositionSelectByTicketSymbolAndMagic(position_ticket, _Symbol, MagicNumber)) { position_open = false; position_ticket = 0; @@ -241,13 +242,31 @@ void CheckEntrySignals() //+------------------------------------------------------------------+ void OpenBuyPosition() { + // Verify no position exists for THIS EA (magic number) on THIS symbol before opening + if(PositionExistsByMagic(_Symbol, MagicNumber)) + { + return; // Position already exists for this EA + } + double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); if(trade.Buy(LotSize, _Symbol, ask, 0, 0, "RSI Scalping Buy")) { - position_ticket = trade.ResultOrder(); - position_open = true; - current_position_type = POSITION_TYPE_BUY; + ulong new_ticket = trade.ResultOrder(); + if(new_ticket > 0) + { + // Verify position was opened for THIS EA (magic number) on THIS symbol + if(PositionSelectByTicketSymbolAndMagic(new_ticket, _Symbol, MagicNumber)) + { + position_ticket = new_ticket; + position_open = true; + current_position_type = POSITION_TYPE_BUY; + } + else + { + Print("Error: Position opened but doesn't match EA magic number or symbol"); + } + } } } @@ -256,13 +275,31 @@ void OpenBuyPosition() //+------------------------------------------------------------------+ void OpenSellPosition() { + // Verify no position exists for THIS EA (magic number) on THIS symbol before opening + if(PositionExistsByMagic(_Symbol, MagicNumber)) + { + return; // Position already exists for this EA + } + double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); if(trade.Sell(LotSize, _Symbol, bid, 0, 0, "RSI Scalping Sell")) { - position_ticket = trade.ResultOrder(); - position_open = true; - current_position_type = POSITION_TYPE_SELL; + ulong new_ticket = trade.ResultOrder(); + if(new_ticket > 0) + { + // Verify position was opened for THIS EA (magic number) on THIS symbol + if(PositionSelectByTicketSymbolAndMagic(new_ticket, _Symbol, MagicNumber)) + { + position_ticket = new_ticket; + position_open = true; + current_position_type = POSITION_TYPE_SELL; + } + else + { + Print("Error: Position opened but doesn't match EA magic number or symbol"); + } + } } } @@ -271,11 +308,20 @@ void OpenSellPosition() //+------------------------------------------------------------------+ void ClosePosition() { - if(trade.PositionClose(position_ticket)) + // Close position using helper that verifies symbol AND magic number for THIS EA + if(ClosePositionByMagic(trade, _Symbol, MagicNumber)) { position_open = false; position_ticket = 0; rsi_against_position = false; bars_against_count = 0; } + else + { + // Position doesn't exist or wrong magic number - reset tracking + position_open = false; + position_ticket = 0; + rsi_against_position = false; + bars_against_count = 0; + } } diff --git a/frontline/MQL5/RSIScalpingTSLA/main.mq5 b/frontline/MQL5/RSIScalpingTSLA/main.mq5 index 6f72f8b..66897e9 100644 --- a/frontline/MQL5/RSIScalpingTSLA/main.mq5 +++ b/frontline/MQL5/RSIScalpingTSLA/main.mq5 @@ -8,6 +8,7 @@ #property version "1.00" #include +#include "../_united/MagicNumberHelpers.mqh" //--- Input parameters input ENUM_TIMEFRAMES TimeFrame = PERIOD_H1; // Timeframe for Analysis @@ -95,8 +96,8 @@ void OnTick() // Check for existing position CheckExistingPosition(); - // Check for new entry signals - if(!position_open) + // Check for new entry signals - only if no position exists for THIS EA (magic number) on THIS symbol + if(!position_open && !PositionExistsByMagic(_Symbol, MagicNumber)) { CheckEntrySignals(); } @@ -129,8 +130,8 @@ void CheckExistingPosition() return; } - // Check if position still exists - if(!PositionSelectByTicket(position_ticket)) + // Check if position still exists with correct magic number AND symbol for THIS EA + if(!PositionSelectByTicketSymbolAndMagic(position_ticket, _Symbol, MagicNumber)) { position_open = false; position_ticket = 0; @@ -241,13 +242,31 @@ void CheckEntrySignals() //+------------------------------------------------------------------+ void OpenBuyPosition() { + // Verify no position exists for THIS EA (magic number) on THIS symbol before opening + if(PositionExistsByMagic(_Symbol, MagicNumber)) + { + return; // Position already exists for this EA + } + double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); if(trade.Buy(LotSize, _Symbol, ask, 0, 0, "RSI Scalping Buy")) { - position_ticket = trade.ResultOrder(); - position_open = true; - current_position_type = POSITION_TYPE_BUY; + ulong new_ticket = trade.ResultOrder(); + if(new_ticket > 0) + { + // Verify position was opened for THIS EA (magic number) on THIS symbol + if(PositionSelectByTicketSymbolAndMagic(new_ticket, _Symbol, MagicNumber)) + { + position_ticket = new_ticket; + position_open = true; + current_position_type = POSITION_TYPE_BUY; + } + else + { + Print("Error: Position opened but doesn't match EA magic number or symbol"); + } + } } } @@ -256,13 +275,31 @@ void OpenBuyPosition() //+------------------------------------------------------------------+ void OpenSellPosition() { + // Verify no position exists for THIS EA (magic number) on THIS symbol before opening + if(PositionExistsByMagic(_Symbol, MagicNumber)) + { + return; // Position already exists for this EA + } + double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); if(trade.Sell(LotSize, _Symbol, bid, 0, 0, "RSI Scalping Sell")) { - position_ticket = trade.ResultOrder(); - position_open = true; - current_position_type = POSITION_TYPE_SELL; + ulong new_ticket = trade.ResultOrder(); + if(new_ticket > 0) + { + // Verify position was opened for THIS EA (magic number) on THIS symbol + if(PositionSelectByTicketSymbolAndMagic(new_ticket, _Symbol, MagicNumber)) + { + position_ticket = new_ticket; + position_open = true; + current_position_type = POSITION_TYPE_SELL; + } + else + { + Print("Error: Position opened but doesn't match EA magic number or symbol"); + } + } } } @@ -271,11 +308,20 @@ void OpenSellPosition() //+------------------------------------------------------------------+ void ClosePosition() { - if(trade.PositionClose(position_ticket)) + // Close position using helper that verifies symbol AND magic number for THIS EA + if(ClosePositionByMagic(trade, _Symbol, MagicNumber)) { position_open = false; position_ticket = 0; rsi_against_position = false; bars_against_count = 0; } + else + { + // Position doesn't exist or wrong magic number - reset tracking + position_open = false; + position_ticket = 0; + rsi_against_position = false; + bars_against_count = 0; + } } diff --git a/frontline/MQL5/RSIScalpingXAUUSD/main.mq5 b/frontline/MQL5/RSIScalpingXAUUSD/main.mq5 index 7336c42..2bd461c 100644 --- a/frontline/MQL5/RSIScalpingXAUUSD/main.mq5 +++ b/frontline/MQL5/RSIScalpingXAUUSD/main.mq5 @@ -8,6 +8,7 @@ #property version "1.00" #include +#include "../_united/MagicNumberHelpers.mqh" //--- Input parameters input ENUM_TIMEFRAMES TimeFrame = PERIOD_H1; // Timeframe for Analysis @@ -95,8 +96,8 @@ void OnTick() // Check for existing position CheckExistingPosition(); - // Check for new entry signals - if(!position_open) + // Check for new entry signals (also verify no position exists with our magic number) + if(!position_open && !PositionExistsByMagic(_Symbol, MagicNumber)) { CheckEntrySignals(); } @@ -129,8 +130,8 @@ void CheckExistingPosition() return; } - // Check if position still exists - if(!PositionSelectByTicket(position_ticket)) + // Check if position still exists with correct magic number + if(!PositionSelectByTicketAndMagic(position_ticket, MagicNumber)) { position_open = false; position_ticket = 0; @@ -271,11 +272,20 @@ void OpenSellPosition() //+------------------------------------------------------------------+ void ClosePosition() { - if(trade.PositionClose(position_ticket)) + // Close position using helper function that verifies symbol AND magic number + if(ClosePositionByMagic(trade, _Symbol, MagicNumber)) { position_open = false; position_ticket = 0; rsi_against_position = false; bars_against_count = 0; } + else + { + // Position doesn't exist or wrong magic number - reset tracking anyway + position_open = false; + position_ticket = 0; + rsi_against_position = false; + bars_against_count = 0; + } } diff --git a/frontline/MQL5/_united/MagicNumberHelpers.mqh b/frontline/MQL5/_united/MagicNumberHelpers.mqh new file mode 100644 index 0000000..dc1fa31 --- /dev/null +++ b/frontline/MQL5/_united/MagicNumberHelpers.mqh @@ -0,0 +1,159 @@ +//+------------------------------------------------------------------+ +//| MagicNumberHelpers.mqh | +//| Copyright 2025, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2025, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +//+------------------------------------------------------------------+ +//| Select position by symbol and magic number | +//+------------------------------------------------------------------+ +bool PositionSelectByMagic(string symbol, ulong magic_number) +{ + // First try to find position by symbol + if(!PositionSelect(symbol)) + return false; + + // Check if the selected position has the correct magic number + if(PositionGetInteger(POSITION_MAGIC) != magic_number) + { + // Position exists but wrong magic number, search all positions + for(int i = PositionsTotal() - 1; i >= 0; i--) + { + if(PositionGetTicket(i) > 0) + { + if(PositionGetString(POSITION_SYMBOL) == symbol && + PositionGetInteger(POSITION_MAGIC) == magic_number) + { + return true; + } + } + } + return false; + } + + return true; +} + +//+------------------------------------------------------------------+ +//| Select position by ticket and verify magic number and symbol | +//+------------------------------------------------------------------+ +bool PositionSelectByTicketAndMagic(ulong ticket, ulong magic_number) +{ + if(!PositionSelectByTicket(ticket)) + return false; + + return (PositionGetInteger(POSITION_MAGIC) == magic_number); +} + +//+------------------------------------------------------------------+ +//| Select position by ticket and verify symbol, magic number | +//+------------------------------------------------------------------+ +bool PositionSelectByTicketSymbolAndMagic(ulong ticket, string symbol, ulong magic_number) +{ + if(!PositionSelectByTicket(ticket)) + return false; + + return (PositionGetString(POSITION_SYMBOL) == symbol && + PositionGetInteger(POSITION_MAGIC) == magic_number); +} + +//+------------------------------------------------------------------+ +//| Check if position exists with correct magic number | +//+------------------------------------------------------------------+ +bool PositionExistsByMagic(string symbol, ulong magic_number) +{ + return PositionSelectByMagic(symbol, magic_number); +} + +//+------------------------------------------------------------------+ +//| Get position ticket by symbol and magic number | +//+------------------------------------------------------------------+ +ulong GetPositionTicketByMagic(string symbol, ulong magic_number) +{ + for(int i = PositionsTotal() - 1; i >= 0; i--) + { + ulong ticket = PositionGetTicket(i); + if(ticket > 0) + { + if(PositionGetString(POSITION_SYMBOL) == symbol && + PositionGetInteger(POSITION_MAGIC) == magic_number) + { + return ticket; + } + } + } + return 0; +} + +//+------------------------------------------------------------------+ +//| Close position by symbol and magic number | +//+------------------------------------------------------------------+ +bool ClosePositionByMagic(CTrade &trade_obj, string symbol, ulong magic_number) +{ + ulong ticket = GetPositionTicketByMagic(symbol, magic_number); + if(ticket == 0) + return false; + + return trade_obj.PositionClose(ticket); +} + +//+------------------------------------------------------------------+ +//| Modify position by symbol and magic number | +//+------------------------------------------------------------------+ +bool ModifyPositionByMagic(CTrade &trade_obj, string symbol, ulong magic_number, + double sl, double tp) +{ + ulong ticket = GetPositionTicketByMagic(symbol, magic_number); + if(ticket == 0) + return false; + + return trade_obj.PositionModify(ticket, sl, tp); +} + +//+------------------------------------------------------------------+ +//| Get position profit by symbol and magic number | +//+------------------------------------------------------------------+ +double GetPositionProfitByMagic(string symbol, ulong magic_number) +{ + if(!PositionSelectByMagic(symbol, magic_number)) + return 0.0; + + return PositionGetDouble(POSITION_PROFIT); +} + +//+------------------------------------------------------------------+ +//| Get position type by symbol and magic number | +//+------------------------------------------------------------------+ +ENUM_POSITION_TYPE GetPositionTypeByMagic(string symbol, ulong magic_number) +{ + if(!PositionSelectByMagic(symbol, magic_number)) + return WRONG_VALUE; + + return (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); +} + +//+------------------------------------------------------------------+ +//| Count positions by symbol and magic number | +//+------------------------------------------------------------------+ +int CountPositionsByMagic(string symbol, ulong magic_number) +{ + int count = 0; + for(int i = PositionsTotal() - 1; i >= 0; i--) + { + ulong ticket = PositionGetTicket(i); + if(ticket > 0) + { + if(PositionGetString(POSITION_SYMBOL) == symbol && + PositionGetInteger(POSITION_MAGIC) == magic_number) + { + count++; + } + } + } + return count; +} + +//+------------------------------------------------------------------+ diff --git a/frontline/MQL5/_united/main.mq5 b/frontline/MQL5/_united/main.mq5 new file mode 100644 index 0000000..29b9147 --- /dev/null +++ b/frontline/MQL5/_united/main.mq5 @@ -0,0 +1,962 @@ +//+------------------------------------------------------------------+ +//| UnitedEA.mq5 | +//| Copyright 2025, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2025, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +#property description "United EA - Runs multiple strategies on multiple instruments with instrument-specific parameters" + +#include +#include "MagicNumberHelpers.mqh" + +//--- Strategy Selection +input bool EnableRSIScalping = true; // Enable RSI Scalping Strategy +input bool EnableMeanReversion = true; // Enable Mean Reversion Strategy +input bool EnableDarvasBox = true; // Enable Darvas Box Strategy +input bool EnableRSICrossOver = true; // Enable RSI Crossover Strategy +input bool EnableRSIMidPoint = true; // Enable RSI Midpoint Strategy + +//--- Instrument Selection for RSI Scalping (each with its own parameters) +input bool EnableRSI_XAUUSD = true; // Enable RSI Scalping on XAUUSD +input bool EnableRSI_APPL = true; // Enable RSI Scalping on APPL +input bool EnableRSI_BTCUSD = true; // Enable RSI Scalping on BTCUSD +input bool EnableRSI_MSFT = true; // Enable RSI Scalping on MSFT +input bool EnableRSI_NVDA = true; // Enable RSI Scalping on NVDA +input bool EnableRSI_TSLA = true; // Enable RSI Scalping on TSLA + +//--- Magic Numbers for RSI Scalping (one per instrument) +input int MagicNumber_RSI_XAUUSD = 129102315; // Magic Number for RSI Scalping XAUUSD +input int MagicNumber_RSI_APPL = 123457; // Magic Number for RSI Scalping APPL +input int MagicNumber_RSI_BTCUSD = 123459123; // Magic Number for RSI Scalping BTCUSD +input int MagicNumber_RSI_MSFT = 123456; // Magic Number for RSI Scalping MSFT +input int MagicNumber_RSI_NVDA = 12345; // Magic Number for RSI Scalping NVDA +input int MagicNumber_RSI_TSLA = 125421321; // Magic Number for RSI Scalping TSLA + +//--- Magic Numbers for Other Strategies +input int MagicNumber_MeanReversion = 12351; // Magic Number for Mean Reversion +input int MagicNumber_DarvasBox = 135790; // Magic Number for Darvas Box +input int MagicNumber_RSICrossOver = 123456; // Magic Number for RSI Crossover +input int MagicNumber_RSIMidPoint = 123457; // Magic Number for RSI Midpoint + +//--- RSI Scalping Parameters: XAUUSD +input ENUM_TIMEFRAMES RSI_XAUUSD_TimeFrame = PERIOD_H1; +input int RSI_XAUUSD_Period = 14; +input double RSI_XAUUSD_Overbought = 71; +input double RSI_XAUUSD_Oversold = 57; +input double RSI_XAUUSD_Target_Buy = 80; +input double RSI_XAUUSD_Target_Sell = 57; +input int RSI_XAUUSD_BarsToWait = 4; +input double RSI_XAUUSD_LotSize = 0.1; + +//--- RSI Scalping Parameters: APPL +input ENUM_TIMEFRAMES RSI_APPL_TimeFrame = PERIOD_M10; +input int RSI_APPL_Period = 14; +input double RSI_APPL_Overbought = 80; +input double RSI_APPL_Oversold = 78; +input double RSI_APPL_Target_Buy = 94; +input double RSI_APPL_Target_Sell = 44; +input int RSI_APPL_BarsToWait = 7; +input double RSI_APPL_LotSize = 25; + +//--- RSI Scalping Parameters: BTCUSD +input ENUM_TIMEFRAMES RSI_BTCUSD_TimeFrame = PERIOD_H1; +input int RSI_BTCUSD_Period = 14; +input double RSI_BTCUSD_Overbought = 90; +input double RSI_BTCUSD_Oversold = 73; +input double RSI_BTCUSD_Target_Buy = 88; +input double RSI_BTCUSD_Target_Sell = 48; +input int RSI_BTCUSD_BarsToWait = 6; +input double RSI_BTCUSD_LotSize = 0.1; + +//--- RSI Scalping Parameters: MSFT +input ENUM_TIMEFRAMES RSI_MSFT_TimeFrame = PERIOD_H3; +input int RSI_MSFT_Period = 14; +input double RSI_MSFT_Overbought = 19; +input double RSI_MSFT_Oversold = 50; +input double RSI_MSFT_Target_Buy = 71; +input double RSI_MSFT_Target_Sell = 70; +input int RSI_MSFT_BarsToWait = 1; +input double RSI_MSFT_LotSize = 50; + +//--- RSI Scalping Parameters: NVDA +input ENUM_TIMEFRAMES RSI_NVDA_TimeFrame = PERIOD_M15; +input int RSI_NVDA_Period = 8; +input double RSI_NVDA_Overbought = 36; +input double RSI_NVDA_Oversold = 38; +input double RSI_NVDA_Target_Buy = 90; +input double RSI_NVDA_Target_Sell = 70; +input int RSI_NVDA_BarsToWait = 5; +input double RSI_NVDA_LotSize = 50; + +//--- RSI Scalping Parameters: TSLA +input ENUM_TIMEFRAMES RSI_TSLA_TimeFrame = PERIOD_H1; +input int RSI_TSLA_Period = 14; +input double RSI_TSLA_Overbought = 54; +input double RSI_TSLA_Oversold = 73; +input double RSI_TSLA_Target_Buy = 87; +input double RSI_TSLA_Target_Sell = 33; +input int RSI_TSLA_BarsToWait = 1; +input double RSI_TSLA_LotSize = 50; + +//--- Mean Reversion Parameters +input int EMA_Periode = 46; +input double PreisSchwelle = 600.0; +input double SteigungSchwelle = 80.0; +input int ÜberwachungTimeout = 800; +input double TrailingStop = 260.0; +input double MeanRev_LotSize = 0.03; +input ENUM_TIMEFRAMES MeanRev_Timeframe = PERIOD_H1; + +//--- Structure for RSI Scalping Strategy Instance +struct RSIScalpingStrategy +{ + string symbol; + int magic_number; + ENUM_TIMEFRAMES timeframe; + int period; + double overbought; + double oversold; + double target_buy; + double target_sell; + int bars_to_wait; + double lot_size; + int rsi_handle; + double rsi_buffer[]; + ulong position_ticket; + bool position_open; + bool buy_position_open; + bool sell_position_open; + datetime last_bar_time; + bool rsi_against_position; + int bars_against_count; + ENUM_POSITION_TYPE current_position_type; +}; + +//--- Global variables +CTrade trade; +RSIScalpingStrategy rsi_strategies[6]; // Array for 6 instruments +int rsi_strategy_count = 0; + +int ema_handle_meanrev = INVALID_HANDLE; +double ema_array[]; +ulong meanrev_ticket = 0; +bool meanrev_position_open = false; +datetime last_bar_time_meanrev = 0; + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() +{ + // Initialize trade object + trade.SetDeviationInPoints(10); + trade.SetTypeFilling(ORDER_FILLING_FOK); + + // Initialize RSI Scalping strategies for each enabled instrument + if(EnableRSIScalping) + { + if(EnableRSI_XAUUSD) + { + InitializeRSIStrategy("XAUUSD", MagicNumber_RSI_XAUUSD, + RSI_XAUUSD_TimeFrame, RSI_XAUUSD_Period, + RSI_XAUUSD_Overbought, RSI_XAUUSD_Oversold, + RSI_XAUUSD_Target_Buy, RSI_XAUUSD_Target_Sell, + RSI_XAUUSD_BarsToWait, RSI_XAUUSD_LotSize); + } + + if(EnableRSI_APPL) + { + // Try different symbol variations for Apple (Pepperstone typically uses AAPL without suffix) + // Try: AAPL, AAPL.US, APPL (in case of typo in broker) + string appl_symbol = GetValidSymbol("AAPL", "AAPL.US"); + if(appl_symbol != "") + { + InitializeRSIStrategy(appl_symbol, MagicNumber_RSI_APPL, + RSI_APPL_TimeFrame, RSI_APPL_Period, + RSI_APPL_Overbought, RSI_APPL_Oversold, + RSI_APPL_Target_Buy, RSI_APPL_Target_Sell, + RSI_APPL_BarsToWait, RSI_APPL_LotSize); + } + else + { + Print("Skipping AAPL strategy - symbol not available"); + } + } + + if(EnableRSI_BTCUSD) + { + InitializeRSIStrategy("BTCUSD", MagicNumber_RSI_BTCUSD, + RSI_BTCUSD_TimeFrame, RSI_BTCUSD_Period, + RSI_BTCUSD_Overbought, RSI_BTCUSD_Oversold, + RSI_BTCUSD_Target_Buy, RSI_BTCUSD_Target_Sell, + RSI_BTCUSD_BarsToWait, RSI_BTCUSD_LotSize); + } + + if(EnableRSI_MSFT) + { + // Pepperstone typically uses MSFT without suffix + string msft_symbol = GetValidSymbol("MSFT", "MSFT.US"); + if(msft_symbol != "") + { + InitializeRSIStrategy(msft_symbol, MagicNumber_RSI_MSFT, + RSI_MSFT_TimeFrame, RSI_MSFT_Period, + RSI_MSFT_Overbought, RSI_MSFT_Oversold, + RSI_MSFT_Target_Buy, RSI_MSFT_Target_Sell, + RSI_MSFT_BarsToWait, RSI_MSFT_LotSize); + } + else + { + Print("Skipping MSFT strategy - symbol not available"); + } + } + + if(EnableRSI_NVDA) + { + // Pepperstone typically uses NVDA without suffix + string nvda_symbol = GetValidSymbol("NVDA", "NVDA.US"); + if(nvda_symbol != "") + { + InitializeRSIStrategy(nvda_symbol, MagicNumber_RSI_NVDA, + RSI_NVDA_TimeFrame, RSI_NVDA_Period, + RSI_NVDA_Overbought, RSI_NVDA_Oversold, + RSI_NVDA_Target_Buy, RSI_NVDA_Target_Sell, + RSI_NVDA_BarsToWait, RSI_NVDA_LotSize); + } + else + { + Print("Skipping NVDA strategy - symbol not available"); + } + } + + if(EnableRSI_TSLA) + { + // Pepperstone typically uses TSLA without suffix + string tsla_symbol = GetValidSymbol("TSLA", "TSLA.US"); + if(tsla_symbol != "") + { + InitializeRSIStrategy(tsla_symbol, MagicNumber_RSI_TSLA, + RSI_TSLA_TimeFrame, RSI_TSLA_Period, + RSI_TSLA_Overbought, RSI_TSLA_Oversold, + RSI_TSLA_Target_Buy, RSI_TSLA_Target_Sell, + RSI_TSLA_BarsToWait, RSI_TSLA_LotSize); + } + else + { + Print("Skipping TSLA strategy - symbol not available"); + } + } + } + + // Initialize Mean Reversion indicator + if(EnableMeanReversion) + { + ema_handle_meanrev = iMA(_Symbol, MeanRev_Timeframe, EMA_Periode, 0, MODE_EMA, PRICE_CLOSE); + if(ema_handle_meanrev == INVALID_HANDLE) + { + Print("Error: Failed to create EMA indicator for Mean Reversion"); + return(INIT_FAILED); + } + ArraySetAsSeries(ema_array, true); + trade.SetExpertMagicNumber(MagicNumber_MeanReversion); + Print("Mean Reversion Strategy initialized with Magic: ", MagicNumber_MeanReversion); + } + + Print("United EA initialized successfully"); + Print("Active RSI Scalping Strategies: ", rsi_strategy_count); + for(int i = 0; i < rsi_strategy_count; i++) + { + Print(" - ", rsi_strategies[i].symbol, " (Magic: ", rsi_strategies[i].magic_number, + ", TF: ", EnumToString(rsi_strategies[i].timeframe), ")"); + } + if(EnableMeanReversion) Print(" - Mean Reversion (Magic: ", MagicNumber_MeanReversion, ")"); + + return(INIT_SUCCEEDED); +} + +//+------------------------------------------------------------------+ +//| Get valid symbol name (try variations) | +//+------------------------------------------------------------------+ +string GetValidSymbol(string preferred, string fallback) +{ + string symbols_to_try[]; + ArrayResize(symbols_to_try, 0); + + // Build list of symbols to try + ArrayResize(symbols_to_try, 1); + symbols_to_try[0] = preferred; + + if(fallback != preferred) + { + ArrayResize(symbols_to_try, 2); + symbols_to_try[1] = fallback; + } + + // If preferred has .US, also try without it + if(StringFind(preferred, ".US") >= 0) + { + string without_suffix = preferred; + StringReplace(without_suffix, ".US", ""); + if(without_suffix != fallback) + { + int size = ArraySize(symbols_to_try); + ArrayResize(symbols_to_try, size + 1); + symbols_to_try[size] = without_suffix; + } + } + + // Try each symbol variation + for(int i = 0; i < ArraySize(symbols_to_try); i++) + { + string test_symbol = symbols_to_try[i]; + + // Try to select the symbol + if(!SymbolSelect(test_symbol, true)) + { + // Symbol might already be selected, check if it exists + if(!SymbolInfoInteger(test_symbol, SYMBOL_SELECT)) + { + continue; // Symbol doesn't exist, try next + } + } + + // Verify symbol is visible + if(SymbolInfoInteger(test_symbol, SYMBOL_VISIBLE)) + { + // Check if we can get price data (symbol is really available) + // During initialization, prices might be 0 if symbol is still synchronizing + // So we'll be lenient and accept the symbol if it's visible + double bid = SymbolInfoDouble(test_symbol, SYMBOL_BID); + double ask = SymbolInfoDouble(test_symbol, SYMBOL_ASK); + + // Accept symbol if it has valid prices OR if it's visible (might be syncing) + if((bid > 0 && ask > 0) || SymbolInfoInteger(test_symbol, SYMBOL_VISIBLE)) + { + if(bid > 0 && ask > 0) + { + Print("Using symbol: ", test_symbol, " (Bid: ", bid, ", Ask: ", ask, ")"); + } + else + { + Print("Using symbol: ", test_symbol, " (synchronizing, prices not yet available)"); + } + return test_symbol; + } + } + } + + Print("Error: Could not find valid symbol for ", preferred, " or ", fallback); + Print("Tried ", ArraySize(symbols_to_try), " symbol variations:"); + for(int i = 0; i < ArraySize(symbols_to_try); i++) + { + Print(" ", (i+1), ". ", symbols_to_try[i]); + } + Print("These symbols may not be available in your broker's symbol list."); + Print("Please add the symbol to Market Watch or disable this strategy."); + + return ""; // Return empty string to indicate failure +} + +//+------------------------------------------------------------------+ +//| Initialize RSI Scalping Strategy for an instrument | +//+------------------------------------------------------------------+ +void InitializeRSIStrategy(string symbol, int magic, ENUM_TIMEFRAMES tf, int period, + double overbought, double oversold, double target_buy, + double target_sell, int bars_wait, double lot_size) +{ + if(rsi_strategy_count >= 6) + { + Print("Error: Maximum 6 RSI strategies allowed"); + return; + } + + // Work directly with array element (no reference) + rsi_strategies[rsi_strategy_count].symbol = symbol; + rsi_strategies[rsi_strategy_count].magic_number = magic; + rsi_strategies[rsi_strategy_count].timeframe = tf; + rsi_strategies[rsi_strategy_count].period = period; + rsi_strategies[rsi_strategy_count].overbought = overbought; + rsi_strategies[rsi_strategy_count].oversold = oversold; + rsi_strategies[rsi_strategy_count].target_buy = target_buy; + rsi_strategies[rsi_strategy_count].target_sell = target_sell; + rsi_strategies[rsi_strategy_count].bars_to_wait = bars_wait; + rsi_strategies[rsi_strategy_count].lot_size = lot_size; + rsi_strategies[rsi_strategy_count].position_ticket = 0; + rsi_strategies[rsi_strategy_count].position_open = false; + rsi_strategies[rsi_strategy_count].buy_position_open = false; + rsi_strategies[rsi_strategy_count].sell_position_open = false; + rsi_strategies[rsi_strategy_count].last_bar_time = 0; + rsi_strategies[rsi_strategy_count].rsi_against_position = false; + rsi_strategies[rsi_strategy_count].bars_against_count = 0; + rsi_strategies[rsi_strategy_count].current_position_type = WRONG_VALUE; + + // Ensure symbol is selected before creating indicator + if(!SymbolSelect(symbol, true)) + { + // Symbol might already be selected, check if it exists + if(!SymbolInfoInteger(symbol, SYMBOL_SELECT)) + { + Print("Error: Failed to select symbol ", symbol, " for RSI indicator"); + Print("Please ensure the symbol exists in Market Watch or add it manually"); + return; + } + } + + // Verify symbol is visible (prices might be 0 during synchronization) + if(!SymbolInfoInteger(symbol, SYMBOL_VISIBLE)) + { + Print("Error: Symbol ", symbol, " is not visible"); + Print("Please add the symbol to Market Watch"); + return; + } + + // Check prices (but don't fail if they're 0 - symbol might be syncing) + double bid = SymbolInfoDouble(symbol, SYMBOL_BID); + double ask = SymbolInfoDouble(symbol, SYMBOL_ASK); + if(bid <= 0 || ask <= 0) + { + Print("Warning: Symbol ", symbol, " has no prices yet (Bid: ", bid, ", Ask: ", ask, ")"); + Print("Symbol may be synchronizing. Will attempt to create indicator anyway..."); + } + + // Create RSI indicator for this symbol + rsi_strategies[rsi_strategy_count].rsi_handle = iRSI(symbol, tf, period, PRICE_CLOSE); + if(rsi_strategies[rsi_strategy_count].rsi_handle == INVALID_HANDLE) + { + int error = GetLastError(); + Print("Error: Failed to create RSI indicator for ", symbol, " (Error: ", error, ")"); + Print("Symbol: ", symbol, ", Timeframe: ", EnumToString(tf), ", Period: ", period); + Print("Please check if the symbol is available in your broker's symbol list"); + return; + } + + ArraySetAsSeries(rsi_strategies[rsi_strategy_count].rsi_buffer, true); + rsi_strategy_count++; + + Print("RSI Scalping Strategy initialized for ", symbol, + " (Magic: ", magic, ", TF: ", EnumToString(tf), ")"); +} + +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) +{ + // Release all RSI indicators + for(int i = 0; i < rsi_strategy_count; i++) + { + if(rsi_strategies[i].rsi_handle != INVALID_HANDLE) + IndicatorRelease(rsi_strategies[i].rsi_handle); + } + + if(ema_handle_meanrev != INVALID_HANDLE) + IndicatorRelease(ema_handle_meanrev); + + Print("United EA deinitialized"); +} + +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() +{ + // Run RSI Scalping Strategies for all enabled instruments + if(EnableRSIScalping) + { + for(int i = 0; i < rsi_strategy_count; i++) + { + RunRSIScalpingStrategy(i); + } + } + + // Run Mean Reversion Strategy + if(EnableMeanReversion) + { + RunMeanReversionStrategy(); + } +} + +//+------------------------------------------------------------------+ +//| RSI Scalping Strategy for a specific instrument (by index) | +//+------------------------------------------------------------------+ +void RunRSIScalpingStrategy(int strategy_index) +{ + // Access strategy by index (no reference needed) + // Check if we have enough bars + if(Bars(rsi_strategies[strategy_index].symbol, rsi_strategies[strategy_index].timeframe) < + rsi_strategies[strategy_index].period + 2) + return; + + // Check if this is a new bar + datetime current_bar_time = iTime(rsi_strategies[strategy_index].symbol, + rsi_strategies[strategy_index].timeframe, 0); + if(current_bar_time == rsi_strategies[strategy_index].last_bar_time) + return; + + rsi_strategies[strategy_index].last_bar_time = current_bar_time; + + // Update RSI values + if(CopyBuffer(rsi_strategies[strategy_index].rsi_handle, 0, 0, 3, + rsi_strategies[strategy_index].rsi_buffer) < 3) + return; + + double rsi_current = rsi_strategies[strategy_index].rsi_buffer[0]; + double rsi_prev = rsi_strategies[strategy_index].rsi_buffer[1]; + double rsi_two_bars_ago = rsi_strategies[strategy_index].rsi_buffer[2]; + + // Set magic number for this strategy + trade.SetExpertMagicNumber(rsi_strategies[strategy_index].magic_number); + + // Check if position exists (regardless of flag state - handles EA restart) + bool position_exists = PositionExistsByMagic(rsi_strategies[strategy_index].symbol, + rsi_strategies[strategy_index].magic_number); + + if(position_exists) + { + // Get actual position type and ticket + ulong ticket = GetPositionTicketByMagic(rsi_strategies[strategy_index].symbol, + rsi_strategies[strategy_index].magic_number); + ENUM_POSITION_TYPE pos_type = GetPositionTypeByMagic(rsi_strategies[strategy_index].symbol, + rsi_strategies[strategy_index].magic_number); + + if(ticket == 0 || pos_type == WRONG_VALUE) + { + // Position doesn't exist or invalid + rsi_strategies[strategy_index].position_open = false; + rsi_strategies[strategy_index].buy_position_open = false; + rsi_strategies[strategy_index].sell_position_open = false; + rsi_strategies[strategy_index].position_ticket = 0; + rsi_strategies[strategy_index].rsi_against_position = false; + rsi_strategies[strategy_index].bars_against_count = 0; + return; + } + + // Update position tracking with fine-grained flags + rsi_strategies[strategy_index].position_ticket = ticket; + rsi_strategies[strategy_index].position_open = true; + rsi_strategies[strategy_index].current_position_type = pos_type; + + if(pos_type == POSITION_TYPE_BUY) + { + rsi_strategies[strategy_index].buy_position_open = true; + rsi_strategies[strategy_index].sell_position_open = false; + } + else if(pos_type == POSITION_TYPE_SELL) + { + rsi_strategies[strategy_index].buy_position_open = false; + rsi_strategies[strategy_index].sell_position_open = true; + } + + // Verify position still exists with correct ticket, symbol, and magic number + if(!PositionSelectByTicketSymbolAndMagic(rsi_strategies[strategy_index].position_ticket, + rsi_strategies[strategy_index].symbol, + rsi_strategies[strategy_index].magic_number)) + { + // Position was closed externally or doesn't match this instrument, reset tracking + rsi_strategies[strategy_index].position_open = false; + rsi_strategies[strategy_index].buy_position_open = false; + rsi_strategies[strategy_index].sell_position_open = false; + rsi_strategies[strategy_index].position_ticket = 0; + rsi_strategies[strategy_index].rsi_against_position = false; + rsi_strategies[strategy_index].bars_against_count = 0; + return; + } + + // Double-check position type matches our tracking (instrument-specific verification) + ENUM_POSITION_TYPE actual_pos_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); + string actual_symbol = PositionGetString(POSITION_SYMBOL); + + if(actual_symbol != rsi_strategies[strategy_index].symbol) + { + Print("Warning: Position symbol mismatch for ", rsi_strategies[strategy_index].symbol, + " - Found: ", actual_symbol, ". Resetting tracking."); + rsi_strategies[strategy_index].position_open = false; + rsi_strategies[strategy_index].buy_position_open = false; + rsi_strategies[strategy_index].sell_position_open = false; + rsi_strategies[strategy_index].position_ticket = 0; + rsi_strategies[strategy_index].rsi_against_position = false; + rsi_strategies[strategy_index].bars_against_count = 0; + return; + } + + // Update position type if it changed (shouldn't happen, but safety check) + if(actual_pos_type != pos_type) + { + Print("Warning: Position type changed for ", rsi_strategies[strategy_index].symbol, + " - Updating from ", EnumToString(pos_type), " to ", EnumToString(actual_pos_type)); + pos_type = actual_pos_type; + rsi_strategies[strategy_index].current_position_type = pos_type; + + if(pos_type == POSITION_TYPE_BUY) + { + rsi_strategies[strategy_index].buy_position_open = true; + rsi_strategies[strategy_index].sell_position_open = false; + } + else if(pos_type == POSITION_TYPE_SELL) + { + rsi_strategies[strategy_index].buy_position_open = false; + rsi_strategies[strategy_index].sell_position_open = true; + } + } + + if(pos_type == POSITION_TYPE_BUY) + { + // Check if RSI is against the position (below oversold) + if(rsi_current < rsi_strategies[strategy_index].oversold) + { + if(!rsi_strategies[strategy_index].rsi_against_position) + { + rsi_strategies[strategy_index].rsi_against_position = true; + rsi_strategies[strategy_index].bars_against_count = 1; + } + else + { + rsi_strategies[strategy_index].bars_against_count++; + } + + // Close position if RSI has been against for Y bars + if(rsi_strategies[strategy_index].bars_against_count >= + rsi_strategies[strategy_index].bars_to_wait) + { + if(ClosePositionByMagic(trade, rsi_strategies[strategy_index].symbol, + rsi_strategies[strategy_index].magic_number)) + { + rsi_strategies[strategy_index].position_open = false; + rsi_strategies[strategy_index].buy_position_open = false; + rsi_strategies[strategy_index].sell_position_open = false; + rsi_strategies[strategy_index].position_ticket = 0; + rsi_strategies[strategy_index].rsi_against_position = false; + rsi_strategies[strategy_index].bars_against_count = 0; + Print("Closed ", rsi_strategies[strategy_index].symbol, " BUY position - RSI against for ", + rsi_strategies[strategy_index].bars_to_wait, " bars"); + } + else + { + Print("Failed to close ", rsi_strategies[strategy_index].symbol, " BUY position - will retry"); + } + return; + } + } + else + { + // RSI is no longer against the position, reset counter + if(rsi_strategies[strategy_index].rsi_against_position) + { + rsi_strategies[strategy_index].rsi_against_position = false; + rsi_strategies[strategy_index].bars_against_count = 0; + } + + // Exit long position when RSI reaches buy target + if(rsi_current >= rsi_strategies[strategy_index].target_buy) + { + if(ClosePositionByMagic(trade, rsi_strategies[strategy_index].symbol, + rsi_strategies[strategy_index].magic_number)) + { + rsi_strategies[strategy_index].position_open = false; + rsi_strategies[strategy_index].buy_position_open = false; + rsi_strategies[strategy_index].sell_position_open = false; + rsi_strategies[strategy_index].position_ticket = 0; + rsi_strategies[strategy_index].rsi_against_position = false; + rsi_strategies[strategy_index].bars_against_count = 0; + Print("Closed ", rsi_strategies[strategy_index].symbol, " BUY position - RSI reached target: ", + rsi_strategies[strategy_index].target_buy); + } + else + { + Print("Failed to close ", rsi_strategies[strategy_index].symbol, " BUY position - will retry"); + } + } + } + } + else if(pos_type == POSITION_TYPE_SELL) + { + // Check if RSI is against the position (above overbought) + if(rsi_current > rsi_strategies[strategy_index].overbought) + { + if(!rsi_strategies[strategy_index].rsi_against_position) + { + rsi_strategies[strategy_index].rsi_against_position = true; + rsi_strategies[strategy_index].bars_against_count = 1; + } + else + { + rsi_strategies[strategy_index].bars_against_count++; + } + + // Close position if RSI has been against for Y bars + if(rsi_strategies[strategy_index].bars_against_count >= + rsi_strategies[strategy_index].bars_to_wait) + { + if(ClosePositionByMagic(trade, rsi_strategies[strategy_index].symbol, + rsi_strategies[strategy_index].magic_number)) + { + rsi_strategies[strategy_index].position_open = false; + rsi_strategies[strategy_index].buy_position_open = false; + rsi_strategies[strategy_index].sell_position_open = false; + rsi_strategies[strategy_index].position_ticket = 0; + rsi_strategies[strategy_index].rsi_against_position = false; + rsi_strategies[strategy_index].bars_against_count = 0; + Print("Closed ", rsi_strategies[strategy_index].symbol, " SELL position - RSI against for ", + rsi_strategies[strategy_index].bars_to_wait, " bars"); + } + else + { + Print("Failed to close ", rsi_strategies[strategy_index].symbol, " SELL position - will retry"); + } + return; + } + } + else + { + // RSI is no longer against the position, reset counter + if(rsi_strategies[strategy_index].rsi_against_position) + { + rsi_strategies[strategy_index].rsi_against_position = false; + rsi_strategies[strategy_index].bars_against_count = 0; + } + + // Exit short position when RSI reaches sell target + if(rsi_current <= rsi_strategies[strategy_index].target_sell) + { + if(ClosePositionByMagic(trade, rsi_strategies[strategy_index].symbol, + rsi_strategies[strategy_index].magic_number)) + { + rsi_strategies[strategy_index].position_open = false; + rsi_strategies[strategy_index].buy_position_open = false; + rsi_strategies[strategy_index].sell_position_open = false; + rsi_strategies[strategy_index].position_ticket = 0; + rsi_strategies[strategy_index].rsi_against_position = false; + rsi_strategies[strategy_index].bars_against_count = 0; + Print("Closed ", rsi_strategies[strategy_index].symbol, " SELL position - RSI reached target: ", + rsi_strategies[strategy_index].target_sell); + } + else + { + Print("Failed to close ", rsi_strategies[strategy_index].symbol, " SELL position - will retry"); + } + } + } + } + } + else + { + // No position exists - reset all tracking flags + rsi_strategies[strategy_index].position_open = false; + rsi_strategies[strategy_index].buy_position_open = false; + rsi_strategies[strategy_index].sell_position_open = false; + rsi_strategies[strategy_index].position_ticket = 0; + rsi_strategies[strategy_index].rsi_against_position = false; + rsi_strategies[strategy_index].bars_against_count = 0; + + // Check for new entry signals (only if no position exists) + if(!PositionExistsByMagic(rsi_strategies[strategy_index].symbol, + rsi_strategies[strategy_index].magic_number)) + { + // Buy signal: RSI crosses from oversold to above oversold + // Only enter if we don't already have a buy position for THIS EA (magic number) on THIS INSTRUMENT + if(!rsi_strategies[strategy_index].buy_position_open) + { + if(rsi_two_bars_ago <= rsi_strategies[strategy_index].oversold && + rsi_prev > rsi_strategies[strategy_index].oversold) + { + double ask = SymbolInfoDouble(rsi_strategies[strategy_index].symbol, SYMBOL_ASK); + if(trade.Buy(rsi_strategies[strategy_index].lot_size, + rsi_strategies[strategy_index].symbol, ask, 0, 0, + "RSI Scalping Buy " + rsi_strategies[strategy_index].symbol)) + { + ulong new_ticket = trade.ResultOrder(); + if(new_ticket > 0) + { + // Verify the position was actually opened for THIS SPECIFIC INSTRUMENT + if(PositionSelectByTicketSymbolAndMagic(new_ticket, + rsi_strategies[strategy_index].symbol, + rsi_strategies[strategy_index].magic_number)) + { + rsi_strategies[strategy_index].position_ticket = new_ticket; + rsi_strategies[strategy_index].position_open = true; + rsi_strategies[strategy_index].buy_position_open = true; + rsi_strategies[strategy_index].sell_position_open = false; + rsi_strategies[strategy_index].current_position_type = POSITION_TYPE_BUY; + Print("Opened BUY position for ", rsi_strategies[strategy_index].symbol, + " (Ticket: ", rsi_strategies[strategy_index].position_ticket, + ", Magic: ", rsi_strategies[strategy_index].magic_number, ")"); + } + else + { + Print("Error: Position opened but doesn't match instrument ", + rsi_strategies[strategy_index].symbol, " - resetting tracking"); + rsi_strategies[strategy_index].position_ticket = 0; + rsi_strategies[strategy_index].position_open = false; + rsi_strategies[strategy_index].buy_position_open = false; + } + } + } + } + } + + // Sell signal: RSI crosses from overbought to below overbought + // Only enter if we don't already have a sell position for THIS EA (magic number) on THIS INSTRUMENT + if(!rsi_strategies[strategy_index].sell_position_open) + { + if(rsi_two_bars_ago >= rsi_strategies[strategy_index].overbought && + rsi_prev < rsi_strategies[strategy_index].overbought) + { + double bid = SymbolInfoDouble(rsi_strategies[strategy_index].symbol, SYMBOL_BID); + if(trade.Sell(rsi_strategies[strategy_index].lot_size, + rsi_strategies[strategy_index].symbol, bid, 0, 0, + "RSI Scalping Sell " + rsi_strategies[strategy_index].symbol)) + { + ulong new_ticket = trade.ResultOrder(); + if(new_ticket > 0) + { + // Verify the position was actually opened for THIS SPECIFIC INSTRUMENT + if(PositionSelectByTicketSymbolAndMagic(new_ticket, + rsi_strategies[strategy_index].symbol, + rsi_strategies[strategy_index].magic_number)) + { + rsi_strategies[strategy_index].position_ticket = new_ticket; + rsi_strategies[strategy_index].position_open = true; + rsi_strategies[strategy_index].buy_position_open = false; + rsi_strategies[strategy_index].sell_position_open = true; + rsi_strategies[strategy_index].current_position_type = POSITION_TYPE_SELL; + Print("Opened SELL position for ", rsi_strategies[strategy_index].symbol, + " (Ticket: ", rsi_strategies[strategy_index].position_ticket, + ", Magic: ", rsi_strategies[strategy_index].magic_number, ")"); + } + else + { + Print("Error: Position opened but doesn't match instrument ", + rsi_strategies[strategy_index].symbol, " - resetting tracking"); + rsi_strategies[strategy_index].position_ticket = 0; + rsi_strategies[strategy_index].position_open = false; + rsi_strategies[strategy_index].sell_position_open = false; + } + } + } + } + } + } + } +} + +//+------------------------------------------------------------------+ +//| Mean Reversion Strategy | +//+------------------------------------------------------------------+ +void RunMeanReversionStrategy() +{ + // Check if this is a new bar + datetime current_bar_time = iTime(_Symbol, MeanRev_Timeframe, 0); + if(current_bar_time == last_bar_time_meanrev) + return; + + last_bar_time_meanrev = current_bar_time; + + // Update EMA values + if(CopyBuffer(ema_handle_meanrev, 0, 0, 3, ema_array) < 3) + return; + + double ema_current = ema_array[0]; + double ema_prev = ema_array[1]; + double current_close = iClose(_Symbol, MeanRev_Timeframe, 0); + + // Set magic number for this strategy + trade.SetExpertMagicNumber(MagicNumber_MeanReversion); + + // Check existing position + if(PositionExistsByMagic(_Symbol, MagicNumber_MeanReversion)) + { + // Manage existing position (trailing stop, exit conditions, etc.) + ManageMeanReversionPosition(ema_current, current_close); + } + else + { + // Check for new entry signals + CheckMeanReversionEntry(ema_current, ema_prev, current_close); + } +} + +//+------------------------------------------------------------------+ +//| Manage Mean Reversion Position | +//+------------------------------------------------------------------+ +void ManageMeanReversionPosition(double ema_current, double current_close) +{ + if(!PositionSelectByMagic(_Symbol, MagicNumber_MeanReversion)) + return; + + double position_profit = PositionGetDouble(POSITION_PROFIT); + double current_price = PositionGetDouble(POSITION_PRICE_CURRENT); + ENUM_POSITION_TYPE position_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); + + double pips_multiplier = (_Digits == 3 || _Digits == 5) ? 10.0 : 1.0; + + // Trailing stop + if(position_profit > 0) + { + if(position_type == POSITION_TYPE_BUY) + { + double new_stop_loss = current_price - (TrailingStop * _Point * pips_multiplier); + double current_stop_loss = PositionGetDouble(POSITION_SL); + if(new_stop_loss > current_stop_loss) + { + ModifyPositionByMagic(trade, _Symbol, MagicNumber_MeanReversion, + new_stop_loss, PositionGetDouble(POSITION_TP)); + } + } + else if(position_type == POSITION_TYPE_SELL) + { + double new_stop_loss = current_price + (TrailingStop * _Point * pips_multiplier); + double current_stop_loss = PositionGetDouble(POSITION_SL); + if(new_stop_loss < current_stop_loss || current_stop_loss == 0) + { + ModifyPositionByMagic(trade, _Symbol, MagicNumber_MeanReversion, + new_stop_loss, PositionGetDouble(POSITION_TP)); + } + } + } + + // Exit when price crosses EMA + bool exit_bullish = (position_type == POSITION_TYPE_SELL && current_close > ema_current); + bool exit_bearish = (position_type == POSITION_TYPE_BUY && current_close < ema_current); + + if(exit_bullish || exit_bearish) + { + ClosePositionByMagic(trade, _Symbol, MagicNumber_MeanReversion); + } +} + +//+------------------------------------------------------------------+ +//| Check Mean Reversion Entry Signals | +//+------------------------------------------------------------------+ +void CheckMeanReversionEntry(double ema_current, double ema_prev, double current_close) +{ + // Simplified entry logic - can be expanded + double pips_multiplier = (_Digits == 3 || _Digits == 5) ? 10.0 : 1.0; + double preis_abstand = MathAbs(current_close - ema_current) / _Point / pips_multiplier; + double steigung = (ema_current - ema_prev) / _Point / pips_multiplier; + + // Entry conditions + bool bullish_signal = (current_close > ema_current && preis_abstand > PreisSchwelle && + MathAbs(steigung) > SteigungSchwelle); + bool bearish_signal = (current_close < ema_current && preis_abstand > PreisSchwelle && + MathAbs(steigung) > SteigungSchwelle); + + if(bullish_signal) + { + if(trade.Buy(MeanRev_LotSize, _Symbol, 0, 0, 0, "Mean Reversion Buy")) + { + meanrev_ticket = trade.ResultOrder(); + meanrev_position_open = true; + } + } + else if(bearish_signal) + { + if(trade.Sell(MeanRev_LotSize, _Symbol, 0, 0, 0, "Mean Reversion Sell")) + { + meanrev_ticket = trade.ResultOrder(); + meanrev_position_open = true; + } + } +} + +//+------------------------------------------------------------------+ diff --git a/lab/EAs/CocktailPlus.mq5 b/lab/EAs/CocktailPlus.mq5 new file mode 100644 index 0000000..e0c449c --- /dev/null +++ b/lab/EAs/CocktailPlus.mq5 @@ -0,0 +1,1069 @@ +//+------------------------------------------------------------------+ +//| EMACrossOver.mq5 | +//| Copyright 2025, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property link "https://www.mql5.com" +#property copyright "Copyright 2025, MetaQuotes Ltd." +#property version "1.00" +#include +//--- Eingabeparameter (Input Parameters) - Optimized Profitable Parameters +input int EMA_Periode = 51; // EMA Periode +input double PreisSchwelle = 300.0; // Preisbewegung Schwelle in Pips +input double SteigungSchwelle = 40.0; // EMA Steigung Schwelle in Pips +input int ÜberwachungTimeout = 1600; // Überwachungszeit in Sekunden +input double TrailingStop = 100.0; // Gleitender Stop in Pips +input double LotGröße = 0.03; // Handelsvolumen +input int MagicNumber = 12350; // Magic Number für Trades +input bool UseSpreadAdjustment = true; // Spread-Anpassung verwenden +input ENUM_TIMEFRAMES Timeframe = PERIOD_H1; // Zeitraum für Analyse +input bool UseBarData = true; // Bar-Daten statt Tick-Daten verwenden +input int MaxTradesPerCrossover = 6; // Maximale Trades pro Crossover-Ereignis +input int ProfitCheckBars = 11; // Bars bis zur Profit-Prüfung +input bool CloseUnprofitableTrades = true; // Unprofitable Trades nach X Bars schließen +//--- V-Shape Reversal Protection Parameters +input bool UseRSIFilter = true; // RSI Filter verwenden (vermeidet Extreme) +input int RSIPeriod = 14; // RSI Periode +input double RSIOverbought = 71.0; // RSI Überkauft Level +input double RSIOversold = 31.0; // RSI Überverkauft Level +input bool UseMomentumConfirmation = true; // Momentum-Bestätigung verwenden +input int MomentumBars = 5; // Bars für Momentum-Prüfung +input bool UsePullbackConfirmation = true; // Pullback-Bestätigung verwenden +input double PullbackThreshold = 0.5; // Pullback-Schwelle (50% der Bewegung) +input bool UseEarlyReversalDetection = true; // Frühe Reversal-Erkennung +input double ReversalThreshold = 0.5; // Reversal-Schwelle (50% Rückgang) +input bool UseMAEProtection = true; // Maximum Adverse Excursion Schutz +input double MAEThreshold = 150.0; // MAE Schwelle in Pips +input int MAECheckBars = 5; // Bars für MAE-Prüfung +//--- V-Shape Reversal Trading Parameters +input bool UseVShapeReversalTrading = true; // V-Shape Reversal Trading aktivieren +input double VShapeReversalStopLoss = 100.0; // Stop Loss für V-Shape Reversal Trades (Pips) +input double VShapeReversalLotSize = 0.01; // Lot-Größe für V-Shape Trades (konservativer) +input bool UseRSI50Crossover = false; // RSI 50 Crossover für Haupt-Trades verwenden +input int RSICrossBars = 4; // Bars für RSI Crossover Bestätigung + +//--- Globale Variablen (Global Variables) +int ema_handle; // EMA Indicator Handle +int rsi_handle; // RSI Indicator Handle +double ema_array[]; // Array für EMA +double rsi_array[]; // Array für RSI +datetime letzte_überwachung_zeit; // Zeit der letzten Überwachung +bool überwachung_aktiv = false; // Überwachungsstatus +bool preis_trigger_aktiv = false; // Preis-Trigger Status +bool steigung_trigger_aktiv = false; // Steigungs-Trigger Status +int ticket = 0; // Trade Ticket +CTrade trade; // CTrade Objekt +int trades_in_current_crossover = 0; // Anzahl Trades im aktuellen Crossover +bool crossover_detected = false; // Crossover erkannt +datetime trade_open_time = 0; // Zeitpunkt des Trade-Öffnens +double entry_price = 0; // Einstiegspreis für MAE-Prüfung +double max_favorable_excursion = 0; // Maximale günstige Bewegung +double max_adverse_excursion = 0; // Maximale ungünstige Bewegung +double trigger_price = 0; // Preis beim Trigger für Pullback-Prüfung +bool is_vshape_trade = false; // Ist aktueller Trade ein V-Shape Reversal Trade +double last_rsi = 50.0; // Letzter RSI-Wert für Crossover-Erkennung +bool rsi_crossed_above_50 = false; // RSI über 50 gekreuzt +bool rsi_crossed_below_50 = false; // RSI unter 50 gekreuzt + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + //--- CTrade konfigurieren (Configure CTrade) + trade.SetExpertMagicNumber(MagicNumber); + trade.SetDeviationInPoints(10); + trade.SetTypeFilling(ORDER_FILLING_IOC); + + //--- EMA Indicator Handle erstellen (Create EMA indicator handle) + ema_handle = iMA(_Symbol, Timeframe, EMA_Periode, 0, MODE_EMA, PRICE_CLOSE); + + if(ema_handle == INVALID_HANDLE) + { + Print("Fehler beim Erstellen des EMA Indicators"); + return(INIT_FAILED); + } + + //--- RSI Indicator Handle erstellen (Create RSI indicator handle) + if(UseRSIFilter || UseVShapeReversalTrading || UseRSI50Crossover) + { + rsi_handle = iRSI(_Symbol, Timeframe, RSIPeriod, PRICE_CLOSE); + + if(rsi_handle == INVALID_HANDLE) + { + Print("Fehler beim Erstellen des RSI Indicators"); + return(INIT_FAILED); + } + + ArraySetAsSeries(rsi_array, true); + + // Initialisiere RSI Tracking (Initialize RSI tracking) + if(UseRSI50Crossover) + { + BerechneRSI(); + if(ArraySize(rsi_array) > 0) + { + last_rsi = rsi_array[0]; + rsi_crossed_above_50 = (last_rsi > 50.0); + rsi_crossed_below_50 = (last_rsi < 50.0); + } + } + } + + //--- Arrays initialisieren (Initialize arrays) + ArraySetAsSeries(ema_array, true); + + //--- Arrays mit aktuellen Werten füllen (Fill arrays with current values) + BerechneEMA(); + if(UseRSIFilter) + { + BerechneRSI(); + } + + Print("EMA EA initialisiert - Periode: ", EMA_Periode, " Timeframe: ", EnumToString(Timeframe), " Handle: ", ema_handle); + if(UseRSIFilter) + { + Print("RSI Filter aktiviert - Periode: ", RSIPeriod); + } + return(INIT_SUCCEEDED); + } + +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { + //--- Indicator Handle freigeben (Release indicator handle) + if(ema_handle != INVALID_HANDLE) + { + IndicatorRelease(ema_handle); + } + + if((UseRSIFilter || UseVShapeReversalTrading || UseRSI50Crossover) && rsi_handle != INVALID_HANDLE) + { + IndicatorRelease(rsi_handle); + } + + Print("EA beendet - Grund: ", reason); +} + +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { + //--- Bar-Daten oder Tick-Daten verwenden (Use bar data or tick data) + if(UseBarData) + { + //--- Nur bei neuen Bars ausführen (Only execute on new bars) + static datetime last_bar_time = 0; + datetime current_bar_time = iTime(_Symbol, Timeframe, 0); + + if(current_bar_time == last_bar_time) + { + return; // Kein neuer Bar, nichts tun + } + + last_bar_time = current_bar_time; + } + + //--- EMA Werte berechnen (Calculate EMA values) + BerechneEMA(); + + //--- RSI Werte berechnen (Calculate RSI values) + if(UseRSIFilter || UseVShapeReversalTrading || UseRSI50Crossover) + { + BerechneRSI(); + + //--- RSI Crossover Tracking für Haupt-Trades (RSI Crossover tracking for main trades) + if(UseRSI50Crossover && ArraySize(rsi_array) >= 2) + { + double current_rsi = rsi_array[0]; + double previous_rsi = rsi_array[1]; + + // Prüfe RSI Crossover über 50 (Check RSI crossover above 50) + if(previous_rsi <= 50.0 && current_rsi > 50.0) + { + rsi_crossed_above_50 = true; + rsi_crossed_below_50 = false; + Print("TRACE: RSI über 50 gekreuzt - Vorher: ", previous_rsi, " Jetzt: ", current_rsi); + } + // Prüfe RSI Crossover unter 50 (Check RSI crossover below 50) + else if(previous_rsi >= 50.0 && current_rsi < 50.0) + { + rsi_crossed_below_50 = true; + rsi_crossed_above_50 = false; + Print("TRACE: RSI unter 50 gekreuzt - Vorher: ", previous_rsi, " Jetzt: ", current_rsi); + } + + last_rsi = current_rsi; + } + } + + //--- Debug: Aktuelle Werte ausgeben (Debug: Output current values) + if(ArraySize(ema_array) > 0) + { + double aktueller_close = iClose(_Symbol, Timeframe, 0); + double ema_aktuell = ema_array[0]; + double ema_vorher = ema_array[1]; + double preis_abstand = MathAbs(aktueller_close - ema_aktuell) / _Point; + double steigung = (ema_aktuell - ema_vorher) / _Point; + + if(UseBarData) + { + Print("=== DEBUG INFO (Neuer Bar) ==="); + Print("Bar Zeit: ", TimeToString(iTime(_Symbol, Timeframe, 0))); + } + else + { + Print("=== DEBUG INFO (Tick) ==="); + } + + Print("Aktueller Close: ", aktueller_close); + Print("EMA: ", ema_aktuell); + Print("Preis-Abstand: ", preis_abstand, " Pips"); + Print("EMA Steigung: ", steigung, " Pips"); + Print("Differenz Close-EMA: ", aktueller_close - ema_aktuell); + Print("Preis-Trigger: ", preis_trigger_aktiv, " Steigungs-Trigger: ", steigung_trigger_aktiv); + Print("Überwachung aktiv: ", überwachung_aktiv); + Print("Position offen: ", PositionSelect(_Symbol)); + Print("Trades im aktuellen Crossover: ", trades_in_current_crossover, "/", MaxTradesPerCrossover); + Print("=================="); + } + + //--- Überwachung prüfen (Check monitoring) + if(überwachung_aktiv) + { + if(UseBarData) + { + // Bar-basierte Überwachungszeit + int bars_since_monitoring = iBarShift(_Symbol, Timeframe, letzte_überwachung_zeit); + int timeout_bars = (int)(ÜberwachungTimeout / PeriodSeconds(Timeframe)); + + if(bars_since_monitoring > timeout_bars) + { + überwachung_aktiv = false; + preis_trigger_aktiv = false; + steigung_trigger_aktiv = false; + Print("Überwachung beendet - Bar-basierte Zeitüberschreitung (", bars_since_monitoring, " Bars)"); + } + } + else + { + // Tick-basierte Überwachungszeit + if(TimeCurrent() - letzte_überwachung_zeit > ÜberwachungTimeout) + { + überwachung_aktiv = false; + preis_trigger_aktiv = false; + steigung_trigger_aktiv = false; + Print("Überwachung beendet - Tick-basierte Zeitüberschreitung"); + } + } + } + + //--- Trigger-Bedingungen prüfen (Check trigger conditions) + PrüfeTrigger(); + + //--- Trade Management (Trade management) + VerwalteTrades(); + + //--- MAE Protection prüfen (Check MAE protection) + if(UseMAEProtection && PositionSelect(_Symbol)) + { + PrüfeMAE(); + } +} + +//+------------------------------------------------------------------+ +//| EMA Berechnung (EMA Calculation) | +//+------------------------------------------------------------------+ +void BerechneEMA() +{ + //--- EMA Werte vom Indicator kopieren (Copy EMA values from indicator) + int copied = CopyBuffer(ema_handle, 0, 0, 3, ema_array); + + if(copied <= 0) + { + Print("TRACE: Fehler beim Kopieren der EMA Werte - Copied: ", copied); + return; + } + + Print("TRACE: EMA Werte kopiert: ", copied, " Bars"); + Print("TRACE: EMA [0]: ", ema_array[0], " [1]: ", ema_array[1], " [2]: ", ema_array[2]); +} + +//+------------------------------------------------------------------+ +//| RSI Berechnung (RSI Calculation) | +//+------------------------------------------------------------------+ +void BerechneRSI() +{ + if(!UseRSIFilter || rsi_handle == INVALID_HANDLE) + return; + + //--- RSI Werte vom Indicator kopieren (Copy RSI values from indicator) + int copied = CopyBuffer(rsi_handle, 0, 0, 3, rsi_array); + + if(copied <= 0) + { + Print("TRACE: Fehler beim Kopieren der RSI Werte - Copied: ", copied); + return; + } + + Print("TRACE: RSI Werte kopiert: ", copied, " Bars"); + Print("TRACE: RSI [0]: ", rsi_array[0], " [1]: ", rsi_array[1], " [2]: ", rsi_array[2]); +} + +//+------------------------------------------------------------------+ +//| Trigger-Bedingungen prüfen (Check trigger conditions) | +//+------------------------------------------------------------------+ +void PrüfeTrigger() +{ + if(ArraySize(ema_array) < 2) + { + Print("TRACE: Array zu klein - Größe: ", ArraySize(ema_array)); + return; + } + + //--- Aktuelle Werte (Current values) + double aktueller_preis = SymbolInfoDouble(_Symbol, SYMBOL_BID); + double aktueller_ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); + double aktueller_close = iClose(_Symbol, Timeframe, 0); + double pips_multiplier = (_Digits == 3 || _Digits == 5) ? 10.0 : 1.0; + + //--- EMA Werte in Variablen (EMA values in variables) + double ema_aktuell = ema_array[0]; + double ema_vorher = ema_array[1]; + + //--- EMA Crossover Erkennung (EMA Crossover Detection) + // Prüfe ob Preis die EMA kreuzt (Check if price crosses EMA) + static double last_close = 0; + static double last_ema = 0; + + if(last_close != 0 && last_ema != 0) + { + bool crossover_bullish = (last_close <= last_ema) && (aktueller_close > ema_aktuell); + bool crossover_bearish = (last_close >= last_ema) && (aktueller_close < ema_aktuell); + + //--- Neues Crossover-Ereignis erkannt (New crossover event detected) + if(crossover_bullish || crossover_bearish) + { + trades_in_current_crossover = 0; // Reset trade counter + Print("TRACE: EMA Crossover erkannt - ", (crossover_bullish ? "BULLISH" : "BEARISH"), " - Trade-Counter zurückgesetzt"); + Print("TRACE: Vorher: Close=", last_close, " EMA=", last_ema, " Jetzt: Close=", aktueller_close, " EMA=", ema_aktuell); + } + } + + //--- Aktuelle Werte für nächsten Vergleich speichern (Save current values for next comparison) + last_close = aktueller_close; + last_ema = ema_aktuell; + + //--- Preisbewegung zur EMA prüfen (Check price action to EMA) + double preis_abstand = MathAbs(aktueller_close - ema_aktuell) / _Point / pips_multiplier; + + Print("TRACE: Preis-Abstand: ", preis_abstand, " Pips (Schwelle: ", PreisSchwelle, ")"); + Print("TRACE: Close: ", aktueller_close, " EMA: ", ema_aktuell); + Print("TRACE: Trades im aktuellen Crossover: ", trades_in_current_crossover, "/", MaxTradesPerCrossover); + + if(preis_abstand > PreisSchwelle && !preis_trigger_aktiv) + { + preis_trigger_aktiv = true; + Print("TRACE: Preis-Trigger aktiviert: ", preis_abstand, " Pips"); + } + + //--- EMA Steigung prüfen (Check EMA slope) + double steigung = (ema_aktuell - ema_vorher) / _Point / pips_multiplier; + + Print("TRACE: EMA Steigung: ", steigung, " Pips (Schwelle: ", SteigungSchwelle, ")"); + + if(MathAbs(steigung) > SteigungSchwelle && !steigung_trigger_aktiv) + { + steigung_trigger_aktiv = true; + Print("TRACE: Steigungs-Trigger aktiviert: ", steigung, " Pips"); + } + + //--- Überwachung starten wenn beide Trigger aktiv sind (Start monitoring when both triggers are active) + if(preis_trigger_aktiv && steigung_trigger_aktiv && !überwachung_aktiv) + { + überwachung_aktiv = true; + trigger_price = aktueller_close; // Preis beim Trigger speichern für Pullback-Prüfung + + if(UseBarData) + { + letzte_überwachung_zeit = iTime(_Symbol, Timeframe, 0); // Aktuelle Bar-Zeit + Print("TRACE: Überwachung gestartet - Beide Trigger aktiv (Bar: ", TimeToString(letzte_überwachung_zeit), ")"); + } + else + { + letzte_überwachung_zeit = TimeCurrent(); // Aktuelle Tick-Zeit + Print("TRACE: Überwachung gestartet - Beide Trigger aktiv (Tick)"); + } + } + + //--- Trade platzieren wenn Überwachung aktiv und Preis über/unter EMA (Place trade when monitoring active and price above/below EMA) + if(überwachung_aktiv) + { + bool bullish_signal = aktueller_close > ema_aktuell; + bool bearish_signal = aktueller_close < ema_aktuell; + + Print("TRACE: Signal Check - Bullish: ", bullish_signal, " Bearish: ", bearish_signal); + Print("TRACE: Close: ", aktueller_close, " EMA: ", ema_aktuell); + Print("TRACE: Differenz: ", aktueller_close - ema_aktuell); + + //--- Trade-Limit prüfen (Check trade limit) + if(trades_in_current_crossover >= MaxTradesPerCrossover) + { + Print("TRACE: Trade-Limit erreicht (", MaxTradesPerCrossover, ") - Kein neuer Trade"); + return; + } + + //--- Neue Strategie: V-Shape Reversal Trading + RSI 50 Crossover für Haupt-Trades + if(!PositionSelect(_Symbol)) + { + //--- 1. Prüfe auf V-Shape Reversal Pattern (Check for V-Shape Reversal Pattern) + if(UseVShapeReversalTrading) + { + ENUM_ORDER_TYPE vshape_direction = PrüfeVShapePattern(aktueller_close, ema_aktuell); + + if(vshape_direction == ORDER_TYPE_BUY) + { + // V-Shape erkannt: Preis war hoch, jetzt fallend -> REVERSE TRADE (SELL) + Print("TRACE: V-SHAPE REVERSAL erkannt - REVERSE TRADE: VERKAUF"); + if(PlatziereVShapeTrade(ORDER_TYPE_SELL, aktueller_close, ema_aktuell)) + { + trades_in_current_crossover++; + entry_price = aktueller_close; + max_favorable_excursion = 0; + max_adverse_excursion = 0; + is_vshape_trade = true; + } + return; // V-Shape Trade platziert, keine weiteren Trades + } + else if(vshape_direction == ORDER_TYPE_SELL) + { + // V-Shape erkannt: Preis war niedrig, jetzt steigend -> REVERSE TRADE (BUY) + Print("TRACE: V-SHAPE REVERSAL erkannt - REVERSE TRADE: KAUF"); + if(PlatziereVShapeTrade(ORDER_TYPE_BUY, aktueller_close, ema_aktuell)) + { + trades_in_current_crossover++; + entry_price = aktueller_close; + max_favorable_excursion = 0; + max_adverse_excursion = 0; + is_vshape_trade = true; + } + return; // V-Shape Trade platziert, keine weiteren Trades + } + } + + //--- 2. Haupt-Trend Trade: Warte auf RSI 50 Crossover (Main Trend Trade: Wait for RSI 50 Crossover) + if(bullish_signal) + { + // Prüfe RSI 50 Crossover für KAUF (Check RSI 50 crossover for BUY) + bool rsi_ready = true; + if(UseRSI50Crossover) + { + rsi_ready = rsi_crossed_above_50 && (ArraySize(rsi_array) > 0 && rsi_array[0] > 50.0); + if(!rsi_ready) + { + Print("TRACE: KAUF-Signal wartet auf RSI 50 Crossover - RSI: ", (ArraySize(rsi_array) > 0 ? rsi_array[0] : 0)); + } + } + + if(rsi_ready) + { + Print("TRACE: Versuche KAUF-Trade zu platzieren (Trade #", trades_in_current_crossover + 1, ")"); + if(PlatziereTrade(ORDER_TYPE_BUY)) + { + trades_in_current_crossover++; + entry_price = aktueller_close; + max_favorable_excursion = 0; + max_adverse_excursion = 0; + is_vshape_trade = false; + rsi_crossed_above_50 = false; // Reset nach Trade + } + } + } + else if(bearish_signal) + { + // Prüfe RSI 50 Crossover für VERKAUF (Check RSI 50 crossover for SELL) + bool rsi_ready = true; + if(UseRSI50Crossover) + { + rsi_ready = rsi_crossed_below_50 && (ArraySize(rsi_array) > 0 && rsi_array[0] < 50.0); + if(!rsi_ready) + { + Print("TRACE: VERKAUF-Signal wartet auf RSI 50 Crossover - RSI: ", (ArraySize(rsi_array) > 0 ? rsi_array[0] : 0)); + } + } + + if(rsi_ready) + { + Print("TRACE: Versuche VERKAUF-Trade zu platzieren (Trade #", trades_in_current_crossover + 1, ")"); + if(PlatziereTrade(ORDER_TYPE_SELL)) + { + trades_in_current_crossover++; + entry_price = aktueller_close; + max_favorable_excursion = 0; + max_adverse_excursion = 0; + is_vshape_trade = false; + rsi_crossed_below_50 = false; // Reset nach Trade + } + } + } + } + else if(PositionSelect(_Symbol)) + { + Print("TRACE: Position bereits offen - kein neuer Trade"); + } + } +} + +//+------------------------------------------------------------------+ +//| V-Shape Pattern Detection | +//+------------------------------------------------------------------+ +ENUM_ORDER_TYPE PrüfeVShapePattern(double aktueller_preis, double ema_aktuell) +{ + if(!UseVShapeReversalTrading || ArraySize(rsi_array) < 3) + return WRONG_VALUE; + + double pips_multiplier = (_Digits == 3 || _Digits == 5) ? 10.0 : 1.0; + double current_rsi = rsi_array[0]; + double previous_rsi = rsi_array[1]; + double rsi_before = rsi_array[2]; + + //--- Hole Preis-Historie für V-Shape Erkennung (Get price history for V-Shape detection) + double close_0 = iClose(_Symbol, Timeframe, 0); + double close_1 = iClose(_Symbol, Timeframe, 1); + double close_2 = iClose(_Symbol, Timeframe, 2); + double close_3 = iClose(_Symbol, Timeframe, 3); + + if(close_1 == 0 || close_2 == 0 || close_3 == 0) + return WRONG_VALUE; + + //--- V-Shape Top Pattern: Preis war hoch (RSI überkauft), jetzt fallend (V-Shape Top Pattern) + // Pattern: Preis steigt -> erreicht Hoch -> fällt (RSI: hoch -> fällt) + bool vshape_top = false; + if(current_rsi < previous_rsi && previous_rsi > RSIOverbought) + { + // RSI war überkauft und fällt jetzt + if(close_0 < close_1 && close_1 < close_2) + { + // Preis fällt kontinuierlich + double price_drop = (close_2 - close_0) / _Point / pips_multiplier; + if(price_drop > 100.0) // Mindest-Fall von 100 Pips + { + vshape_top = true; + Print("TRACE: V-SHAPE TOP erkannt - RSI fällt von ", previous_rsi, " zu ", current_rsi); + Print("TRACE: Preis fällt von ", close_2, " zu ", close_0, " (", price_drop, " Pips)"); + } + } + } + + //--- V-Shape Bottom Pattern: Preis war niedrig (RSI überverkauft), jetzt steigend (V-Shape Bottom Pattern) + // Pattern: Preis fällt -> erreicht Tief -> steigt (RSI: niedrig -> steigt) + bool vshape_bottom = false; + if(current_rsi > previous_rsi && previous_rsi < RSIOversold) + { + // RSI war überverkauft und steigt jetzt + if(close_0 > close_1 && close_1 > close_2) + { + // Preis steigt kontinuierlich + double price_rise = (close_0 - close_2) / _Point / pips_multiplier; + if(price_rise > 100.0) // Mindest-Anstieg von 100 Pips + { + vshape_bottom = true; + Print("TRACE: V-SHAPE BOTTOM erkannt - RSI steigt von ", previous_rsi, " zu ", current_rsi); + Print("TRACE: Preis steigt von ", close_2, " zu ", close_0, " (", price_rise, " Pips)"); + } + } + } + + if(vshape_top) + return ORDER_TYPE_SELL; // Reverse Trade: Verkauf bei V-Shape Top + else if(vshape_bottom) + return ORDER_TYPE_BUY; // Reverse Trade: Kauf bei V-Shape Bottom + + return WRONG_VALUE; // Kein V-Shape erkannt +} + +//+------------------------------------------------------------------+ +//| V-Shape Reversal Trade platzieren (Place V-Shape Reversal Trade)| +//+------------------------------------------------------------------+ +bool PlatziereVShapeTrade(ENUM_ORDER_TYPE order_type, double aktueller_preis, double ema_aktuell) +{ + double pips_multiplier = (_Digits == 3 || _Digits == 5) ? 10.0 : 1.0; + double stop_loss_pips = VShapeReversalStopLoss; + double stop_loss_price = 0; + + Print("TRACE: Versuche V-SHAPE REVERSAL Trade zu platzieren - Typ: ", (order_type == ORDER_TYPE_BUY) ? "KAUF" : "VERKAUF"); + Print("TRACE: Lot: ", VShapeReversalLotSize, " Stop Loss: ", stop_loss_pips, " Pips"); + + //--- Berechne Stop Loss (Calculate Stop Loss) + if(order_type == ORDER_TYPE_BUY) + { + stop_loss_price = aktueller_preis - (stop_loss_pips * _Point * pips_multiplier); + } + else + { + stop_loss_price = aktueller_preis + (stop_loss_pips * _Point * pips_multiplier); + } + + bool success = false; + + if(order_type == ORDER_TYPE_BUY) + { + success = trade.Buy(VShapeReversalLotSize, _Symbol, 0, stop_loss_price, 0, "V-Shape Reversal Trade"); + } + else + { + success = trade.Sell(VShapeReversalLotSize, _Symbol, 0, stop_loss_price, 0, "V-Shape Reversal Trade"); + } + + if(success) + { + ticket = (int)trade.ResultOrder(); + Print("TRACE: V-SHAPE Trade erfolgreich platziert: ", (order_type == ORDER_TYPE_BUY) ? "KAUF" : "VERKAUF", " Ticket: ", ticket); + Print("TRACE: Stop Loss: ", stop_loss_price); + + //--- Trade-Öffnungszeit speichern (Save trade opening time) + trade_open_time = iTime(_Symbol, Timeframe, 0); + Print("TRACE: Trade-Öffnungszeit: ", TimeToString(trade_open_time)); + + //--- Überwachung zurücksetzen (Reset monitoring) + überwachung_aktiv = false; + preis_trigger_aktiv = false; + steigung_trigger_aktiv = false; + + return true; + } + else + { + Print("TRACE: Fehler beim Platzieren des V-SHAPE Trades - Retcode: ", trade.ResultRetcode()); + Print("TRACE: Fehlerbeschreibung: ", trade.ResultRetcodeDescription()); + + return false; + } +} + +//+------------------------------------------------------------------+ +//| Trade platzieren (Place trade) | +//+------------------------------------------------------------------+ +bool PlatziereTrade(ENUM_ORDER_TYPE order_type) +{ + Print("TRACE: Versuche Trade zu platzieren - Typ: ", (order_type == ORDER_TYPE_BUY) ? "KAUF" : "VERKAUF"); + Print("TRACE: Lot: ", LotGröße); + + bool success = false; + + if(order_type == ORDER_TYPE_BUY) + { + success = trade.Buy(LotGröße, _Symbol, 0, 0, 0, "EMA Crossover Trade"); + } + else + { + success = trade.Sell(LotGröße, _Symbol, 0, 0, 0, "EMA Crossover Trade"); + } + + if(success) + { + ticket = (int)trade.ResultOrder(); + Print("TRACE: Trade erfolgreich platziert: ", (order_type == ORDER_TYPE_BUY) ? "KAUF" : "VERKAUF", " Ticket: ", ticket); + + //--- Trade-Öffnungszeit speichern (Save trade opening time) + trade_open_time = iTime(_Symbol, Timeframe, 0); + Print("TRACE: Trade-Öffnungszeit: ", TimeToString(trade_open_time)); + + //--- Überwachung zurücksetzen (Reset monitoring) + überwachung_aktiv = false; + preis_trigger_aktiv = false; + steigung_trigger_aktiv = false; + + return true; + } + else + { + Print("TRACE: Fehler beim Platzieren des Trades - Retcode: ", trade.ResultRetcode()); + Print("TRACE: Fehlerbeschreibung: ", trade.ResultRetcodeDescription()); + + return false; + } +} + +//+------------------------------------------------------------------+ +//| Trades verwalten (Manage trades) | +//+------------------------------------------------------------------+ +void VerwalteTrades() +{ + if(!PositionSelect(_Symbol)) + return; + + double position_profit = PositionGetDouble(POSITION_PROFIT); + double position_open_price = PositionGetDouble(POSITION_PRICE_OPEN); + double current_price = PositionGetDouble(POSITION_PRICE_CURRENT); + ENUM_POSITION_TYPE position_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); + + double pips_multiplier = (_Digits == 3 || _Digits == 5) ? 10.0 : 1.0; + double trailing_stop_pips = TrailingStop; + + //--- Für V-Shape Trades: Tighter Trailing Stop (For V-Shape trades: Tighter trailing stop) + if(is_vshape_trade) + { + trailing_stop_pips = VShapeReversalStopLoss * 0.5; // 50% des Stop Loss als Trailing + Print("TRACE: V-Shape Trade - Verwendeter Trailing Stop: ", trailing_stop_pips, " Pips"); + } + + //--- Gleitender Stop (Trailing Stop) - nur wenn Position im Profit ist + if(position_profit > 0) // Only apply trailing stop when in profit + { + if(position_type == POSITION_TYPE_BUY) + { + double new_stop_loss = current_price - (trailing_stop_pips * _Point * pips_multiplier); + double current_stop_loss = PositionGetDouble(POSITION_SL); + + // Only move stop loss if new stop is higher than current stop + if(new_stop_loss > current_stop_loss) + { + ÄndereStopLoss(new_stop_loss); + } + } + else if(position_type == POSITION_TYPE_SELL) + { + double new_stop_loss = current_price + (trailing_stop_pips * _Point * pips_multiplier); + double current_stop_loss = PositionGetDouble(POSITION_SL); + + // Only move stop loss if new stop is lower than current stop + if(new_stop_loss < current_stop_loss || current_stop_loss == 0) + { + ÄndereStopLoss(new_stop_loss); + } + } + } + + //--- Ausstieg bei Preis unter/über EMA (Exit when price below/above EMA) + if(ArraySize(ema_array) >= 1) + { + double aktueller_close = iClose(_Symbol, Timeframe, 0); + double ema_aktuell = ema_array[0]; + bool exit_bullish = (position_type == POSITION_TYPE_SELL && aktueller_close > ema_aktuell); + bool exit_bearish = (position_type == POSITION_TYPE_BUY && aktueller_close < ema_aktuell); + + if(exit_bullish || exit_bearish) + { + Print("TRACE: Ausstiegssignal - Close: ", aktueller_close, " EMA: ", ema_aktuell); + SchließePosition("EMA Crossover Exit"); + + Print("TRACE: Position geschlossen - Trade-Counter bleibt bei ", trades_in_current_crossover); + } + } + + //--- Profit-Prüfung nach X Bars (Profit check after X bars) + if(CloseUnprofitableTrades && trade_open_time != 0 && PositionSelect(_Symbol)) + { + Print("TRACE: Profit-Prüfung aktiviert - CloseUnprofitableTrades: ", CloseUnprofitableTrades); + PrüfeProfitNachBars(); + } + else if(!CloseUnprofitableTrades) + { + Print("TRACE: Profit-Prüfung deaktiviert - CloseUnprofitableTrades: ", CloseUnprofitableTrades); + } +} + +//+------------------------------------------------------------------+ +//| Profit-Prüfung nach X Bars (Profit check after X bars) | +//+------------------------------------------------------------------+ +void PrüfeProfitNachBars() +{ + if(!PositionSelect(_Symbol)) + { + return; // Keine Position offen + } + + datetime current_bar_time = iTime(_Symbol, Timeframe, 0); + int bars_since_trade_open = iBarShift(_Symbol, Timeframe, trade_open_time); + + Print("TRACE: Bars seit Trade-Öffnung: ", bars_since_trade_open, "/", ProfitCheckBars); + + //--- Prüfe ob genügend Bars vergangen sind (Check if enough bars have passed) + if(bars_since_trade_open >= ProfitCheckBars) + { + double position_profit = PositionGetDouble(POSITION_PROFIT); + double position_volume = PositionGetDouble(POSITION_VOLUME); + ENUM_POSITION_TYPE position_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); + + Print("TRACE: Profit-Prüfung nach ", ProfitCheckBars, " Bars"); + Print("TRACE: Position Profit: ", position_profit, " USD"); + + //--- Schließe Position wenn nicht im Profit (Close position if not in profit) + if(position_profit <= 0) + { + Print("TRACE: Position nicht im Profit - Schließe Position"); + SchließePosition("Profit Check - Unprofitable"); + + //--- Trade-Öffnungszeit zurücksetzen (Reset trade opening time) + trade_open_time = 0; + Print("TRACE: Trade-Öffnungszeit zurückgesetzt"); + } + else + { + Print("TRACE: Position im Profit - Behalte Position"); + //--- Trade-Öffnungszeit zurücksetzen um weitere Prüfungen zu vermeiden (Reset to avoid further checks) + trade_open_time = 0; + } + } +} + +//+------------------------------------------------------------------+ +//| Stop Loss ändern (Modify Stop Loss) | +//+------------------------------------------------------------------+ +void ÄndereStopLoss(double new_stop_loss) +{ + Print("TRACE: Versuche Stop Loss zu ändern auf: ", new_stop_loss); + + bool success = trade.PositionModify(_Symbol, new_stop_loss, PositionGetDouble(POSITION_TP)); + + if(success) + { + Print("TRACE: Stop Loss erfolgreich geändert auf: ", new_stop_loss); + } + else + { + Print("TRACE: Fehler beim Ändern des Stop Loss - Retcode: ", trade.ResultRetcode()); + Print("TRACE: Fehlerbeschreibung: ", trade.ResultRetcodeDescription()); + } +} + +//+------------------------------------------------------------------+ +//| Position schließen (Close position) | +//+------------------------------------------------------------------+ +void SchließePosition(string reason = "Unbekannt") +{ + Print("TRACE: Versuche Position zu schließen - Grund: ", reason); + + bool success = trade.PositionClose(_Symbol); + + if(success) + { + Print("TRACE: Position erfolgreich geschlossen - Grund: ", reason); + //--- Reset MAE tracking (Reset MAE tracking) + entry_price = 0; + max_favorable_excursion = 0; + max_adverse_excursion = 0; + is_vshape_trade = false; + } + else + { + Print("TRACE: Fehler beim Schließen der Position - Retcode: ", trade.ResultRetcode()); + Print("TRACE: Fehlerbeschreibung: ", trade.ResultRetcodeDescription()); + } +} + +//+------------------------------------------------------------------+ +//| V-Shape Reversal Protection Check | +//+------------------------------------------------------------------+ +bool PrüfeVShapeSchutz(ENUM_ORDER_TYPE order_type, double aktueller_preis, double ema_aktuell) +{ + double pips_multiplier = (_Digits == 3 || _Digits == 5) ? 10.0 : 1.0; + + //--- 1. RSI Filter: Vermeide Einstieg bei extremen RSI-Werten (RSI Filter: Avoid entry at extreme RSI values) + if(UseRSIFilter) + { + if(ArraySize(rsi_array) < 1) + { + Print("TRACE: RSI Array zu klein für Filter"); + return false; + } + + double current_rsi = rsi_array[0]; + + if(order_type == ORDER_TYPE_BUY) + { + // Vermeide Einstieg wenn RSI überkauft (Avoid entry when RSI overbought) + if(current_rsi > RSIOverbought) + { + Print("TRACE: RSI Filter blockiert KAUF - RSI: ", current_rsi, " > ", RSIOverbought); + return false; + } + } + else if(order_type == ORDER_TYPE_SELL) + { + // Vermeide Einstieg wenn RSI überverkauft (Avoid entry when RSI oversold) + if(current_rsi < RSIOversold) + { + Print("TRACE: RSI Filter blockiert VERKAUF - RSI: ", current_rsi, " < ", RSIOversold); + return false; + } + } + + Print("TRACE: RSI Filter bestanden - RSI: ", current_rsi); + } + + //--- 2. Momentum Confirmation: Prüfe ob Momentum in Richtung des Trades zeigt (Momentum Confirmation) + if(UseMomentumConfirmation) + { + if(!PrüfeMomentum(order_type)) + { + Print("TRACE: Momentum-Bestätigung fehlgeschlagen"); + return false; + } + Print("TRACE: Momentum-Bestätigung erfolgreich"); + } + + //--- 3. Pullback Confirmation: Warte auf Pullback statt Einstieg am Extrem (Pullback Confirmation) + if(UsePullbackConfirmation && trigger_price != 0) + { + double price_movement = MathAbs(aktueller_preis - trigger_price) / _Point / pips_multiplier; + double distance_to_ema = MathAbs(aktueller_preis - ema_aktuell) / _Point / pips_multiplier; + double initial_distance = MathAbs(trigger_price - ema_aktuell) / _Point / pips_multiplier; + + if(initial_distance > 0) + { + double pullback_ratio = distance_to_ema / initial_distance; + + // Erlaube Einstieg nur wenn Preis zurück zur EMA gezogen ist (Allow entry only if price pulled back toward EMA) + if(pullback_ratio > (1.0 - PullbackThreshold)) + { + Print("TRACE: Pullback-Bestätigung fehlgeschlagen - Ratio: ", pullback_ratio, " (benötigt < ", (1.0 - PullbackThreshold), ")"); + return false; + } + Print("TRACE: Pullback-Bestätigung erfolgreich - Ratio: ", pullback_ratio); + } + } + + return true; +} + +//+------------------------------------------------------------------+ +//| Momentum Confirmation Check | +//+------------------------------------------------------------------+ +bool PrüfeMomentum(ENUM_ORDER_TYPE order_type) +{ + if(MomentumBars < 1) + return true; + + //--- Prüfe ob die letzten Bars Momentum in Richtung des Trades zeigen (Check if recent bars show momentum in trade direction) + double close_0 = iClose(_Symbol, Timeframe, 0); + double close_n = iClose(_Symbol, Timeframe, MomentumBars); + + if(close_n == 0) + return true; // Nicht genug Daten (Not enough data) + + if(order_type == ORDER_TYPE_BUY) + { + // Für KAUF: Preis sollte höher sein als vor N Bars (For BUY: Price should be higher than N bars ago) + if(close_0 <= close_n) + { + Print("TRACE: Momentum fehlt für KAUF - Close[0]: ", close_0, " Close[", MomentumBars, "]: ", close_n); + return false; + } + } + else if(order_type == ORDER_TYPE_SELL) + { + // Für VERKAUF: Preis sollte niedriger sein als vor N Bars (For SELL: Price should be lower than N bars ago) + if(close_0 >= close_n) + { + Print("TRACE: Momentum fehlt für VERKAUF - Close[0]: ", close_0, " Close[", MomentumBars, "]: ", close_n); + return false; + } + } + + return true; +} + +//+------------------------------------------------------------------+ +//| Maximum Adverse Excursion Check | +//+------------------------------------------------------------------+ +void PrüfeMAE() +{ + if(!PositionSelect(_Symbol) || entry_price == 0) + return; + + double current_price = PositionGetDouble(POSITION_PRICE_CURRENT); + ENUM_POSITION_TYPE position_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); + double pips_multiplier = (_Digits == 3 || _Digits == 5) ? 10.0 : 1.0; + + double current_excursion = 0; + + if(position_type == POSITION_TYPE_BUY) + { + current_excursion = (current_price - entry_price) / _Point / pips_multiplier; + } + else if(position_type == POSITION_TYPE_SELL) + { + current_excursion = (entry_price - current_price) / _Point / pips_multiplier; + } + + //--- Update maximale Bewegungen (Update maximum movements) + if(current_excursion > max_favorable_excursion) + { + max_favorable_excursion = current_excursion; + } + + if(current_excursion < -max_adverse_excursion) + { + max_adverse_excursion = -current_excursion; + } + + //--- Prüfe ob MAE-Schwelle überschritten wurde (Check if MAE threshold exceeded) + if(max_adverse_excursion > MAEThreshold) + { + // Prüfe ob genug Bars vergangen sind (Check if enough bars have passed) + datetime current_bar_time = iTime(_Symbol, Timeframe, 0); + int bars_since_entry = iBarShift(_Symbol, Timeframe, trade_open_time); + + if(bars_since_entry >= MAECheckBars) + { + double position_profit = PositionGetDouble(POSITION_PROFIT); + + // Schließe nur wenn Position nicht im Profit ist (Close only if position not in profit) + if(position_profit <= 0) + { + Print("TRACE: MAE-Schwelle überschritten - MAE: ", max_adverse_excursion, " Pips (Schwelle: ", MAEThreshold, ")"); + Print("TRACE: Position Profit: ", position_profit, " - Schließe Position"); + SchließePosition("MAE Protection - Excessive Adverse Excursion"); + } + else + { + Print("TRACE: MAE-Schwelle überschritten aber Position im Profit - MAE: ", max_adverse_excursion, " Profit: ", position_profit); + } + } + } +} + +//+------------------------------------------------------------------+ +//| Early Reversal Detection | +//+------------------------------------------------------------------+ +bool PrüfeFrüheReversal(ENUM_POSITION_TYPE position_type, double aktueller_preis, double ema_aktuell) +{ + if(!UseEarlyReversalDetection || entry_price == 0) + return false; + + double pips_multiplier = (_Digits == 3 || _Digits == 5) ? 10.0 : 1.0; + double price_to_ema = MathAbs(aktueller_preis - ema_aktuell) / _Point / pips_multiplier; + double entry_to_ema = MathAbs(entry_price - ema_aktuell) / _Point / pips_multiplier; + + if(entry_to_ema == 0) + return false; + + //--- Prüfe ob Preis sich zu weit zurück zur EMA bewegt hat (Check if price moved too far back toward EMA) + double reversal_ratio = price_to_ema / entry_to_ema; + + if(reversal_ratio < ReversalThreshold) + { + // Preis hat sich mehr als X% zurück zur EMA bewegt - mögliche Reversal (Price moved more than X% back toward EMA - possible reversal) + Print("TRACE: Frühe Reversal erkannt - Ratio: ", reversal_ratio, " (Schwelle: ", ReversalThreshold, ")"); + + // Prüfe ob Position im Verlust ist (Check if position is in loss) + if(PositionSelect(_Symbol)) + { + double position_profit = PositionGetDouble(POSITION_PROFIT); + if(position_profit <= 0) + { + Print("TRACE: Reversal erkannt und Position im Verlust - Schließe Position"); + return true; + } + } + } + + return false; +} + +//+------------------------------------------------------------------+ \ No newline at end of file