Merge pull request #33 from zhutoutoutousan/develop

Update
This commit is contained in:
zhutoutoutousan
2026-05-27 16:13:50 +02:00
committed by GitHub
122 changed files with 5259 additions and 12459 deletions

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

+26 -23
View File
@@ -23,14 +23,14 @@ def test_mt5_connection():
print("3. Try logging into MT5 manually first")
return False
print(" MT5 initialized successfully")
print("[OK] MT5 initialized successfully")
# Get account info
account_info = mt5.account_info()
if account_info is None:
print("WARNING: Could not get account info")
else:
print(f" Account: {account_info.login}")
print(f"[OK] Account: {account_info.login}")
print(f" Server: {account_info.server}")
print(f" Balance: ${account_info.balance:.2f}")
@@ -41,9 +41,9 @@ def test_mt5_connection():
for symbol in test_symbols:
symbol_info = mt5.symbol_info(symbol)
if symbol_info is None:
print(f" {symbol}: Not available")
print(f"[FAIL] {symbol}: Not available")
else:
print(f" {symbol}: Available")
print(f"[OK] {symbol}: Available")
print(f" Bid: {symbol_info.bid:.5f}, Ask: {symbol_info.ask:.5f}")
print(f" Spread: {symbol_info.spread} points")
@@ -56,31 +56,34 @@ def test_mt5_connection():
rates = mt5.copy_rates_range(symbol, timeframe, start_date, end_date)
if rates is None or len(rates) == 0:
print(f" Could not retrieve historical data for {symbol}")
print(f"[FAIL] Could not retrieve historical data for {symbol}")
print(" Make sure you have historical data in MT5")
else:
print(f" Retrieved {len(rates)} bars for {symbol}")
print(f"[OK] Retrieved {len(rates)} bars for {symbol}")
print(f" Date range: {datetime.fromtimestamp(rates[0]['time'])} to {datetime.fromtimestamp(rates[-1]['time'])}")
# Test indicator creation
# Test indicator creation (optional: some MetaTrader5 Python wheels omit terminal indicator APIs)
print("\nTesting indicator creation...")
rsi_handle = mt5.iRSI(symbol, timeframe, 14, mt5.PRICE_CLOSE)
if rsi_handle == mt5.INVALID_HANDLE:
print("✗ Failed to create RSI indicator")
if not hasattr(mt5, "iRSI") or not hasattr(mt5, "iMA"):
print("[SKIP] mt5.iRSI / mt5.iMA not available in this MetaTrader5 build; skipping handle tests.")
print(" (Historical data + account checks above are enough for the Python backtest harness.)")
else:
print("✓ RSI indicator created successfully")
# Get RSI values
rsi_values = mt5.copy_buffer(rsi_handle, 0, 0, 10)
if rsi_values is not None:
print(f" Latest RSI values: {rsi_values[-3:]}")
mt5.indicator_release(rsi_handle)
ema_handle = mt5.iMA(symbol, timeframe, 50, 0, mt5.MODE_EMA, mt5.PRICE_CLOSE)
if ema_handle == mt5.INVALID_HANDLE:
print("✗ Failed to create EMA indicator")
else:
print("✓ EMA indicator created successfully")
mt5.indicator_release(ema_handle)
rsi_handle = mt5.iRSI(symbol, timeframe, 14, mt5.PRICE_CLOSE)
if rsi_handle == mt5.INVALID_HANDLE:
print("[FAIL] Failed to create RSI indicator")
else:
print("[OK] RSI indicator created successfully")
rsi_values = mt5.copy_buffer(rsi_handle, 0, 0, 10)
if rsi_values is not None:
print(f" Latest RSI values: {rsi_values[-3:]}")
mt5.indicator_release(rsi_handle)
ema_handle = mt5.iMA(symbol, timeframe, 50, 0, mt5.MODE_EMA, mt5.PRICE_CLOSE)
if ema_handle == mt5.INVALID_HANDLE:
print("[FAIL] Failed to create EMA indicator")
else:
print("[OK] EMA indicator created successfully")
mt5.indicator_release(ema_handle)
# Cleanup
mt5.shutdown()
@@ -1,27 +0,0 @@
; saved on 2026.04.22
; genetic optimization set for DarvasBoxXAUUSD/main.mq5
; load in MT5 Strategy Tester -> Inputs -> Load
;
; === Core Darvas Box Parameters ===
BoxPeriod=165||80||5||280||Y
BoxDeviation=25140||8000||500||50000||Y
VolumeThreshold=938||200||25||2500||Y
StopLoss=1665||600||50||4000||Y
TakeProfit=3685||1200||75||8000||Y
EnableLogging=false||false||0||true||N
BoxColor=255||0||1||16777215||N
BoxWidth=1||1||1||3||N
;
; === Trend Confirmation Parameters ===
TrendTimeframe=16386||16385||1||16388||Y
MA_Period=125||20||5||260||Y
MA_Method=1||0||1||3||Y
MA_Price=6||0||1||6||Y
TrendThreshold=4.94||1.0||0.2||20.0||Y
;
; === Volume Analysis Parameters ===
VolumeMA_Period=110||20||5||220||Y
VolumeThresholdMultiplier=1.5||1.0||0.1||3.5||Y
;
; === Execution / ID ===
MagicNumber=135790||135790||1||1357900||N
@@ -1,443 +0,0 @@
//+------------------------------------------------------------------+
//| DarvasBox.mq5 |
//| Copyright 2024, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
#include <Trade\Trade.mqh>
#include <Indicators\Trend.mqh>
#include <Indicators\Volumes.mqh>
#include "../_united/MagicNumberHelpers.mqh"
// Input parameters
input int BoxPeriod = 165; // Period for Darvas Box calculation
input double BoxDeviation = 25140; // Box deviation in points
input int VolumeThreshold = 938; // Minimum volume for confirmation
input double StopLoss = 1665; // Stop loss in points (increased for BTCUSD)
input double TakeProfit = 3685; // Take profit in points (increased for BTCUSD)
input bool EnableLogging = false; // Enable detailed logging
input color BoxColor = clrBlue; // Color for Darvas Box
input int BoxWidth = 1; // Width of box lines
// Trend confirmation parameters
input ENUM_TIMEFRAMES TrendTimeframe = PERIOD_H2; // Timeframe for trend analysis
input int MA_Period = 125; // Moving Average period for trend
input ENUM_MA_METHOD MA_Method = MODE_EMA; // Moving Average method
input ENUM_APPLIED_PRICE MA_Price = PRICE_WEIGHTED; // Price type for MA
input double TrendThreshold = 4.94; // Trend strength threshold
// Volume analysis parameters
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;
bool boxFormed = false;
datetime lastBoxTime = 0;
string boxName = "DarvasBox_";
double minStopLevel = 0;
double point = 0;
CTrade trade;
// Indicator handles
int maHandle;
int volumeHandle;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Initialize indicators and variables
boxHigh = 0;
boxLow = 0;
boxFormed = false;
lastBoxTime = 0;
// Get symbol properties
point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
minStopLevel = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL) * point;
// Initialize indicators
maHandle = iMA(_Symbol, TrendTimeframe, MA_Period, 0, MA_Method, MA_Price);
volumeHandle = iVolumes(_Symbol, PERIOD_CURRENT, VOLUME_TICK);
if(maHandle == INVALID_HANDLE || volumeHandle == INVALID_HANDLE)
{
Print("Error creating indicators");
return(INIT_FAILED);
}
// Configure trade object
trade.SetDeviationInPoints(10);
trade.SetTypeFilling(ORDER_FILLING_IOC);
trade.SetAsyncMode(false);
trade.SetExpertMagicNumber(MagicNumber);
if(EnableLogging)
{
Print("Darvas Box Expert Advisor initialized");
Print("Symbol: ", _Symbol);
Print("Point: ", point);
Print("Minimum Stop Level: ", minStopLevel);
}
// Delete any existing box objects
ObjectsDeleteAll(0, boxName);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Draw Darvas Box on chart |
//+------------------------------------------------------------------+
void DrawDarvasBox()
{
if(!boxFormed) return;
datetime time1 = iTime(_Symbol, PERIOD_H1, BoxPeriod);
datetime time2 = iTime(_Symbol, PERIOD_H1, 0);
// Delete old box
ObjectsDeleteAll(0, boxName);
// Draw box
ObjectCreate(0, boxName + "Top", OBJ_TREND, 0, time1, boxHigh, time2, boxHigh);
ObjectCreate(0, boxName + "Bottom", OBJ_TREND, 0, time1, boxLow, time2, boxLow);
// Set box properties
ObjectSetInteger(0, boxName + "Top", OBJPROP_COLOR, BoxColor);
ObjectSetInteger(0, boxName + "Bottom", OBJPROP_COLOR, BoxColor);
ObjectSetInteger(0, boxName + "Top", OBJPROP_WIDTH, BoxWidth);
ObjectSetInteger(0, boxName + "Bottom", OBJPROP_WIDTH, BoxWidth);
ObjectSetInteger(0, boxName + "Top", OBJPROP_RAY_RIGHT, true);
ObjectSetInteger(0, boxName + "Bottom", OBJPROP_RAY_RIGHT, true);
}
//+------------------------------------------------------------------+
//| Calculate Darvas Box levels |
//+------------------------------------------------------------------+
void CalculateDarvasBox()
{
double high = 0;
double low = DBL_MAX;
// Find highest high and lowest low in the period
for(int i = 0; i < BoxPeriod; i++)
{
high = MathMax(high, iHigh(_Symbol, PERIOD_H1, i));
low = MathMin(low, iLow(_Symbol, PERIOD_H1, i));
}
double range = high - low;
double allowedRange = BoxDeviation * _Point;
if(EnableLogging)
{
Print("Box Calculation - High: ", high, " Low: ", low, " Range: ", range, " Allowed Range: ", allowedRange);
}
// Check if box is formed
if(range <= allowedRange)
{
boxHigh = high;
boxLow = low;
boxFormed = true;
lastBoxTime = iTime(_Symbol, PERIOD_CURRENT, 0);
// Draw the box
DrawDarvasBox();
if(EnableLogging)
Print("Box Formed - High: ", boxHigh, " Low: ", boxLow, " Time: ", lastBoxTime);
}
else
{
boxFormed = false;
// Delete box if it exists
ObjectsDeleteAll(0, boxName);
}
}
//+------------------------------------------------------------------+
//| Validate and adjust stop levels |
//+------------------------------------------------------------------+
bool ValidateStopLevels(double price, double &sl, double &tp, ENUM_ORDER_TYPE orderType)
{
double minSlDistance = MathMax(minStopLevel, StopLoss * point);
double minTpDistance = MathMax(minStopLevel, TakeProfit * point);
if(EnableLogging)
{
Print("Minimum SL Distance: ", minSlDistance);
Print("Minimum TP Distance: ", minTpDistance);
}
// Adjust stop loss
if(orderType == ORDER_TYPE_BUY)
{
sl = price - minSlDistance;
tp = price + minTpDistance;
if(EnableLogging)
{
Print("Buy Order Levels:");
Print("Entry: ", price);
Print("Stop Loss: ", sl);
Print("Take Profit: ", tp);
}
}
else // ORDER_TYPE_SELL
{
sl = price + minSlDistance;
tp = price - minTpDistance;
if(EnableLogging)
{
Print("Sell Order Levels:");
Print("Entry: ", price);
Print("Stop Loss: ", sl);
Print("Take Profit: ", tp);
}
}
return true;
}
//+------------------------------------------------------------------+
//| Check trend direction and strength |
//+------------------------------------------------------------------+
bool IsTrendFavorable(ENUM_ORDER_TYPE orderType)
{
double ma[];
ArraySetAsSeries(ma, true);
if(CopyBuffer(maHandle, 0, 0, 2, ma) <= 0)
return false;
double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double trendStrength = MathAbs(currentPrice - ma[0]) / point;
if(EnableLogging)
Print("Trend Strength: ", trendStrength);
if(orderType == ORDER_TYPE_BUY)
return (currentPrice > ma[0] && trendStrength > TrendThreshold);
else
return (currentPrice < ma[0] && trendStrength > TrendThreshold);
}
//+------------------------------------------------------------------+
//| Check volume conditions |
//+------------------------------------------------------------------+
bool CheckVolumeConditions()
{
double volumes[];
ArraySetAsSeries(volumes, true);
if(CopyBuffer(volumeHandle, 0, 0, VolumeMA_Period + 1, volumes) <= 0)
return false;
double volumeMA = 0;
for(int i = 1; i <= VolumeMA_Period; i++)
volumeMA += volumes[i];
volumeMA /= VolumeMA_Period;
double currentVolume = volumes[0];
double volumeRatio = currentVolume / volumeMA;
if(EnableLogging)
Print("Volume Ratio: ", volumeRatio);
return (volumeRatio > VolumeThresholdMultiplier);
}
//+------------------------------------------------------------------+
//| Place trade order |
//+------------------------------------------------------------------+
bool PlaceOrder(ENUM_ORDER_TYPE orderType, double price, double sl, double tp)
{
// Validate and adjust stop levels
if(!ValidateStopLevels(price, sl, tp, orderType))
{
if(EnableLogging)
Print("Invalid stop levels after adjustment");
return false;
}
// Check trend and volume conditions
if(!IsTrendFavorable(orderType))
{
if(EnableLogging)
Print("Trend not favorable for trade");
return false;
}
if(!CheckVolumeConditions())
{
if(EnableLogging)
Print("Volume conditions not met");
return false;
}
if(EnableLogging)
{
Print("Order Details:");
Print("Type: ", EnumToString(orderType));
Print("Price: ", price);
Print("Stop Loss: ", sl);
Print("Take Profit: ", tp);
}
bool result = false;
if(orderType == ORDER_TYPE_BUY)
{
result = trade.Buy(0.01, _Symbol, price, sl, tp, "Darvas Box Breakout");
}
else
{
result = trade.Sell(0.01, _Symbol, price, sl, tp, "Darvas Box Breakdown");
}
if(EnableLogging)
{
if(result)
Print((orderType == ORDER_TYPE_BUY ? "Buy" : "Sell"), " Order Placed Successfully");
else
Print((orderType == ORDER_TYPE_BUY ? "Buy" : "Sell"), " Order Failed - Error: ", trade.ResultRetcode(), " Description: ", trade.ResultRetcodeDescription());
}
return result;
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// Calculate new box levels
CalculateDarvasBox();
// Check for trading signals
if(boxFormed)
{
double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double currentVolume = iVolume(_Symbol, PERIOD_CURRENT, 0);
if(EnableLogging)
{
Print("Current Price: ", currentPrice, " Box High: ", boxHigh, " Box Low: ", boxLow);
Print("Current Volume: ", currentVolume, " Volume Threshold: ", VolumeThreshold);
}
// Check for breakout above box
if(currentPrice > boxHigh && currentVolume > VolumeThreshold)
{
if(EnableLogging)
Print("Breakout Signal Detected - Price above box high");
// Buy signal
if(!PositionExistsByMagic(_Symbol, MagicNumber)) // No existing positions with our magic number
{
double sl = currentPrice - StopLoss * _Point;
double tp = currentPrice + TakeProfit * _Point;
if(EnableLogging)
Print("Preparing Buy Order - Price: ", currentPrice, " SL: ", sl, " TP: ", tp);
PlaceOrder(ORDER_TYPE_BUY, currentPrice, sl, tp);
}
else if(EnableLogging)
Print("Skipping Buy Signal - Position already exists");
}
// Check for breakdown below box
if(currentPrice < boxLow && currentVolume > VolumeThreshold)
{
if(EnableLogging)
Print("Breakdown Signal Detected - Price below box low");
// Sell signal
if(!PositionExistsByMagic(_Symbol, MagicNumber)) // No existing positions with our magic number
{
double sl = currentPrice + StopLoss * _Point;
double tp = currentPrice - TakeProfit * _Point;
if(EnableLogging)
Print("Preparing Sell Order - Price: ", currentPrice, " SL: ", sl, " TP: ", tp);
PlaceOrder(ORDER_TYPE_SELL, currentPrice, sl, tp);
}
else if(EnableLogging)
Print("Skipping Sell Signal - Position already exists");
}
}
else if(EnableLogging)
Print("No Box Formed - Waiting for consolidation");
}
//+------------------------------------------------------------------+
//| Get last error description |
//+------------------------------------------------------------------+
string GetLastErrorDescription()
{
string errorDescription;
switch(GetLastError())
{
case 0: errorDescription = "No error"; break;
case 1: errorDescription = "No error, but result unknown"; break;
case 2: errorDescription = "Common error"; break;
case 3: errorDescription = "Invalid trade parameters"; break;
case 4: errorDescription = "Trade server is busy"; break;
case 5: errorDescription = "Old version of the client terminal"; break;
case 6: errorDescription = "No connection with trade server"; break;
case 7: errorDescription = "Not enough rights"; break;
case 8: errorDescription = "Too frequent requests"; break;
case 9: errorDescription = "Malfunctional trade operation"; break;
case 64: errorDescription = "Account disabled"; break;
case 65: errorDescription = "Invalid account"; break;
case 128: errorDescription = "Trade timeout"; break;
case 129: errorDescription = "Invalid price"; break;
case 130: errorDescription = "Invalid stops"; break;
case 131: errorDescription = "Invalid trade volume"; break;
case 132: errorDescription = "Market is closed"; break;
case 133: errorDescription = "Trade is disabled"; break;
case 134: errorDescription = "Not enough money"; break;
case 135: errorDescription = "Price changed"; break;
case 136: errorDescription = "Off quotes"; break;
case 137: errorDescription = "Broker is busy"; break;
case 138: errorDescription = "Requote"; break;
case 139: errorDescription = "Order is locked"; break;
case 140: errorDescription = "Long positions only allowed"; break;
case 141: errorDescription = "Too many requests"; break;
case 145: errorDescription = "Modification denied because order is too close to market"; break;
case 146: errorDescription = "Trade context is busy"; break;
case 147: errorDescription = "Expirations are denied by broker"; break;
case 148: errorDescription = "Amount of open and pending orders has reached the limit"; break;
case 149: errorDescription = "Hedging is prohibited"; break;
case 150: errorDescription = "Prohibited by FIFO rules"; break;
default: errorDescription = "Unknown error"; break;
}
return errorDescription;
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// Delete all box objects
ObjectsDeleteAll(0, boxName);
if(EnableLogging)
Print("Expert Advisor deinitialized - Reason: ", reason);
}
@@ -1,628 +0,0 @@
//+------------------------------------------------------------------+
//| EMACrossOver.mq5 |
//| Copyright 2025, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.01"
#include <Trade\Trade.mqh>
#include "../_united/MagicNumberHelpers.mqh"
//--- Eingabeparameter (Input Parameters) - Optimized Profitable Parameters
input int EMA_Periode = 50; // EMA Periode
input double PreisSchwelle = 700.0; // Preisbewegung Schwelle in Pips
input double SteigungSchwelle = 25.0; // EMA Steigung Schwelle in Pips
input int ÜberwachungTimeout = 340; // Überwachungszeit in Sekunden
input double TrailingStop = 370.0; // Gleitender Stop in Pips
input bool UseTrailingStop = true; // Gleitenden Stop anwenden
input double TrailingActivationPips = 0.0; // Mindestgewinn in Pips bis Trail startet (0 = Konto-Profit>0)
input bool UseStaleStopLossExit = false; // schließen wenn SL zu lange nicht angepasst wurde
input int StaleStopLossSeconds = 33800; // Sekunden ohne SL-Änderung -> Close (0 = aus)
input double LotGröße = 0.07; // Handelsvolumen
input int MagicNumber = 135790; // 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 = 3; // 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
input bool UseWeeklyADXFilter = true; // W1 ADX Trendfilter aktivieren
input int WeeklyADXPeriod = 15; // ADX-Periode auf W1
input double WeeklyADXMin = 40.0; // Minimaler ADX fuer Trendfreigabe
input int WeeklyADXBarShift = 2; // 1=letzte geschlossene W1-Kerze
input bool WeeklyADXUseDirection = true; // +DI/-DI Richtung mitpruefen
//--- Globale Variablen (Global Variables)
int ema_handle; // EMA Indicator Handle
double ema_array[]; // Array für EMA
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
datetime g_last_sl_adjust_success_time = 0; // letzte erfolgreiche SL-Verschiebung (Stale-Exit)
//+------------------------------------------------------------------+
//| Weekly ADX trend filter |
//+------------------------------------------------------------------+
bool IsWeeklyADXTrendFavorable(ENUM_ORDER_TYPE order_type)
{
if(!UseWeeklyADXFilter)
return true;
int adxShift = WeeklyADXBarShift;
if(adxShift < 0)
adxShift = 0;
int adx_handle = iADX(_Symbol, PERIOD_W1, WeeklyADXPeriod);
if(adx_handle == INVALID_HANDLE)
{
Print("TRACE: Weekly ADX Handle ungültig - Filter blockiert Entry");
return false;
}
double adx_buf[], plus_di_buf[], minus_di_buf[];
ArraySetAsSeries(adx_buf, true);
ArraySetAsSeries(plus_di_buf, true);
ArraySetAsSeries(minus_di_buf, true);
bool ok_adx = (CopyBuffer(adx_handle, 0, adxShift, 1, adx_buf) > 0);
bool ok_plus = (CopyBuffer(adx_handle, 1, adxShift, 1, plus_di_buf) > 0);
bool ok_minus = (CopyBuffer(adx_handle, 2, adxShift, 1, minus_di_buf) > 0);
IndicatorRelease(adx_handle);
if(!ok_adx || !ok_plus || !ok_minus)
{
Print("TRACE: Weekly ADX Daten nicht verfügbar - Filter blockiert Entry");
return false;
}
double adx_value = adx_buf[0];
double plus_di = plus_di_buf[0];
double minus_di = minus_di_buf[0];
bool strength_ok = (adx_value >= WeeklyADXMin);
bool direction_ok = true;
if(WeeklyADXUseDirection)
{
if(order_type == ORDER_TYPE_BUY)
direction_ok = (plus_di > minus_di);
else
direction_ok = (minus_di > plus_di);
}
Print("TRACE: Weekly ADX Filter | ADX=", DoubleToString(adx_value, 2),
" +DI=", DoubleToString(plus_di, 2),
" -DI=", DoubleToString(minus_di, 2),
" strength_ok=", strength_ok,
" direction_ok=", direction_ok);
return (strength_ok && direction_ok);
}
//+------------------------------------------------------------------+
//| 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);
}
//--- Arrays initialisieren (Initialize arrays)
ArraySetAsSeries(ema_array, true);
//--- Arrays mit aktuellen Werten füllen (Fill arrays with current values)
BerechneEMA();
Print("EMA EA initialisiert - Periode: ", EMA_Periode, " Timeframe: ", EnumToString(Timeframe), " Handle: ", ema_handle);
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);
}
Print("EA beendet - Grund: ", reason);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
static datetime last_bar_time = 0;
const datetime current_bar_time = iTime(_Symbol, Timeframe, 0);
const bool new_bar = (current_bar_time != last_bar_time);
const bool has_position = PositionExistsByMagic(_Symbol, (ulong)MagicNumber);
// Offene Positionen: Management jeden Tick (Trailing / Stale-SL). Sonst bei Bar-Modus nur neuer Bar.
if(UseBarData)
{
if(!new_bar && !has_position)
return;
if(new_bar)
last_bar_time = current_bar_time;
}
//--- EMA Werte berechnen (Calculate EMA values)
BerechneEMA();
const bool run_signals = (!UseBarData || new_bar);
//--- Debug / Überwachung / Entry nur bei neuem Bar (Bar-Modus) oder jeden Tick (Tick-Modus)
if(run_signals && 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: ", PositionExistsByMagic(_Symbol, (ulong)MagicNumber));
Print("Trades im aktuellen Crossover: ", trades_in_current_crossover, "/", MaxTradesPerCrossover);
Print("==================");
}
if(run_signals)
{
//--- Überwachung prüfen (Check monitoring)
if(überwachung_aktiv)
{
if(UseBarData)
{
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
{
if(TimeCurrent() - letzte_überwachung_zeit > ÜberwachungTimeout)
{
überwachung_aktiv = false;
preis_trigger_aktiv = false;
steigung_trigger_aktiv = false;
Print("Überwachung beendet - Tick-basierte Zeitüberschreitung");
}
}
}
PrüfeTrigger();
}
VerwalteTrades();
}
//+------------------------------------------------------------------+
//| 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]);
}
//+------------------------------------------------------------------+
//| 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;
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;
}
if(bullish_signal && !PositionExistsByMagic(_Symbol, (ulong)MagicNumber))
{
if(!IsWeeklyADXTrendFavorable(ORDER_TYPE_BUY))
{
Print("TRACE: Weekly ADX blockiert BUY-Entry");
return;
}
Print("TRACE: Versuche KAUF-Trade zu platzieren (Trade #", trades_in_current_crossover + 1, ")");
if(PlatziereTrade(ORDER_TYPE_BUY))
{
trades_in_current_crossover++;
}
}
else if(bearish_signal && !PositionExistsByMagic(_Symbol, (ulong)MagicNumber))
{
if(!IsWeeklyADXTrendFavorable(ORDER_TYPE_SELL))
{
Print("TRACE: Weekly ADX blockiert SELL-Entry");
return;
}
Print("TRACE: Versuche VERKAUF-Trade zu platzieren (Trade #", trades_in_current_crossover + 1, ")");
if(PlatziereTrade(ORDER_TYPE_SELL))
{
trades_in_current_crossover++;
}
}
else if(PositionExistsByMagic(_Symbol, (ulong)MagicNumber))
{
Print("TRACE: Position bereits offen - kein neuer Trade");
}
}
}
//+------------------------------------------------------------------+
//| 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);
g_last_sl_adjust_success_time = 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;
}
}
//+------------------------------------------------------------------+
//| Mindestgewinn fuer Trailing erreicht? |
//+------------------------------------------------------------------+
bool TrailingActivationReached(const double position_profit, const ENUM_POSITION_TYPE position_type,
const double pips_multiplier)
{
if(TrailingActivationPips <= 0.0)
return (position_profit > 0.0);
const double open_px = PositionGetDouble(POSITION_PRICE_OPEN);
if(position_type == POSITION_TYPE_BUY)
{
const double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
return ((bid - open_px) / _Point / pips_multiplier >= TrailingActivationPips);
}
const double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
return ((open_px - ask) / _Point / pips_multiplier >= TrailingActivationPips);
}
//+------------------------------------------------------------------+
//| Trades verwalten (Manage trades) |
//+------------------------------------------------------------------+
void VerwalteTrades()
{
if(!PositionSelectByMagic(_Symbol, (ulong)MagicNumber))
return;
if(UseStaleStopLossExit && StaleStopLossSeconds > 0)
{
const datetime stale_ref = (g_last_sl_adjust_success_time > 0)
? g_last_sl_adjust_success_time
: (datetime)PositionGetInteger(POSITION_TIME);
if(TimeCurrent() - stale_ref >= StaleStopLossSeconds)
{
SchließePosition("Stale stop loss - keine SL-Anpassung");
return;
}
}
double position_profit = PositionGetDouble(POSITION_PROFIT);
ENUM_POSITION_TYPE position_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
double pips_multiplier = (_Digits == 3 || _Digits == 5) ? 10.0 : 1.0;
const double trail_dist = TrailingStop * _Point * pips_multiplier;
const int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
const long stops_level = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
const double min_dist = (double)stops_level * _Point;
//--- Gleitender Stop (Trailing Stop)
if(UseTrailingStop && TrailingStop > 0.0 && TrailingActivationReached(position_profit, position_type, pips_multiplier))
{
if(position_type == POSITION_TYPE_BUY)
{
const double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double new_stop_loss = NormalizeDouble(bid - trail_dist, digits);
if(min_dist > 0.0 && bid - new_stop_loss < min_dist)
new_stop_loss = NormalizeDouble(bid - min_dist, digits);
const double current_stop_loss = PositionGetDouble(POSITION_SL);
if(new_stop_loss < bid && new_stop_loss > 0.0 && new_stop_loss > current_stop_loss)
ÄndereStopLoss(new_stop_loss);
}
else if(position_type == POSITION_TYPE_SELL)
{
const double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double new_stop_loss = NormalizeDouble(ask + trail_dist, digits);
if(min_dist > 0.0 && new_stop_loss - ask < min_dist)
new_stop_loss = NormalizeDouble(ask + min_dist, digits);
const double current_stop_loss = PositionGetDouble(POSITION_SL);
if(new_stop_loss > ask && new_stop_loss > 0.0 &&
(new_stop_loss < current_stop_loss || current_stop_loss == 0.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 && PositionExistsByMagic(_Symbol, (ulong)MagicNumber))
{
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(!PositionSelectByMagic(_Symbol, (ulong)MagicNumber))
{
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 = ModifyPositionByMagic(trade, _Symbol, (ulong)MagicNumber, new_stop_loss, PositionGetDouble(POSITION_TP));
if(success)
{
g_last_sl_adjust_success_time = TimeCurrent();
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 = ClosePositionByMagic(trade, _Symbol, (ulong)MagicNumber);
if(success)
{
g_last_sl_adjust_success_time = 0;
Print("TRACE: Position erfolgreich geschlossen - Grund: ", reason);
}
else
{
Print("TRACE: Fehler beim Schließen der Position - Retcode: ", trade.ResultRetcode());
Print("TRACE: Fehlerbeschreibung: ", trade.ResultRetcodeDescription());
}
}
//+------------------------------------------------------------------+
Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

@@ -1,295 +0,0 @@
// Input Parameters
#include <Trade\Trade.mqh>
#include "../_united/MagicNumberHelpers.mqh"
input group "Trade Management"
input int MagicNumber = 7;
input int rsiPeriod = 19; // RSI period
input int overboughtLevel = 93; // Overbought level (RSI > 70 for sell)
input int oversoldLevel = 22; // Oversold level (RSI < 30 for buy)
input double entryRSIBuySpread = 0;
input double entryRSISellSpread = 0;
input double lotSize = 0.1; // Trade lot size
input int slippage = 3; // Slippage for orders
input int cooldownSeconds = 209; // Cooldown period in seconds
input ENUM_TIMEFRAMES TimeFrame1 = PERIOD_M1; // RSI Timeframe
input ENUM_TIMEFRAMES TimeFrame2 = PERIOD_M1; // EMA Timeframe
input ENUM_TIMEFRAMES BarTimeFrame = PERIOD_M12; // EMA Timeframe
input int emaPeriod = 140; // EMA period
input double emaSlopeThreshold = 105; // EMA slope threshold for trend strength
input double exitBuyRSI = 86;
input double exitSellRSI = 10;
input double TrailingStop = 295;
input double emaDistanceThreshold = 165;
input int tradingHourOneBegin = 24;
input int tradingHourOneEnd = 22;
input int tradingHourTwoBegin = 6;
input int tradingHourTwoEnd = 19;
datetime bartime;
// RSI Handle
int rsiHandle;
input bool Sunday =false; // Sunday
input bool Monday =false; // Monday
input bool Tuesday =true; // Tuesday
input bool Wednesday=true; // Wednesday
input bool Thursday =true; // Thursday
input bool Friday =false; // Friday
input bool Saturday =false; // Saturday
bool WeekDays[7];
void WeekDays_Init()
{
WeekDays[0]=Sunday;
WeekDays[1]=Monday;
WeekDays[2]=Tuesday;
WeekDays[3]=Wednesday;
WeekDays[4]=Thursday;
WeekDays[5]=Friday;
WeekDays[6]=Saturday;
}
bool WeekDays_Check(datetime aTime)
{
MqlDateTime stm;
TimeToStruct(aTime,stm);
return(WeekDays[stm.day_of_week]);
}
// EMA Handle
int emaHandle;
double previousRSIDef = 0;
// Create CTrade object for executing trades
CTrade trade;
// Track the last trade time
datetime lastTradeTime = 0;
void OnInit() {
WeekDays_Init();
// Create RSI handle
rsiHandle = iRSI(_Symbol, TimeFrame1, rsiPeriod, PRICE_CLOSE);
if (rsiHandle == INVALID_HANDLE) {
Print("Error creating RSI handle: ", GetLastError());
return;
}
// Create EMA handle
emaHandle = iMA(_Symbol, TimeFrame2, emaPeriod, 0, MODE_EMA, PRICE_CLOSE);
if (emaHandle == INVALID_HANDLE) {
Print("Error creating EMA handle: ", GetLastError());
return;
}
// Initialization successful
Print("RSI and EMA Reversal Strategy Initialized.");
}
void OnTick() {
if(bartime==iTime(_Symbol,BarTimeFrame,0))return;
bartime=iTime(_Symbol,BarTimeFrame,0);
// Check if RSI data is available
double rsi[];
if (CopyBuffer(rsiHandle, 0, 0, 2, rsi) <= 0) {
Print("Error copying RSI data: ", GetLastError());
return;
}
// Check if EMA data is available
double ema[];
if (CopyBuffer(emaHandle, 0, 0, 2, ema) <= 0) {
Print("Error copying EMA data: ", GetLastError());
return;
}
// Get the current time
datetime currentTime = TimeCurrent();
int currentHour = TimeHour(TimeCurrent());
if(!WeekDays_Check(TimeTradeServer())) {
Close_Position_MN(MagicNumber);
return;
}
if (!(currentHour < tradingHourOneEnd && currentHour > tradingHourOneBegin || currentHour < tradingHourTwoEnd && currentHour > tradingHourTwoBegin))
{
Close_Position_MN(MagicNumber);
return; // Prevent further trading during this time
}
// Ensure there is at least one position
bool hasPosition = PositionExistsByMagic(_Symbol, MagicNumber);
// Get the current and previous RSI values
double currentRSI = rsi[0];
double previousRSI = rsi[1];
if(previousRSIDef == 0) {
previousRSIDef = currentRSI;
return;
}
// Get the current and previous EMA values
double currentEMA = ema[0];
double previousEMA = ema[1];
// Calculate the EMA slope (difference between current and previous EMA values)
double emaSlope = (currentEMA - previousEMA) * 100;
Print(emaSlope);
double closeCurr = iClose(Symbol(), Period(), 0); // Close of current bar
// ** NEW CODE: Calculate distance to EMA and adjust score **
double priceToEmaDistance = (closeCurr - currentEMA) * 10; // Distance between the current price and the EMA
Print("priceToEmaDistance");
Print(priceToEmaDistance);
// Determine if there are existing buy or sell positions
bool isBuyPosition = false;
bool isSellPosition = false;
if (hasPosition) {
if (PositionSelectByMagic(_Symbol, MagicNumber)) {
int positionType = PositionGetInteger(POSITION_TYPE);
if (positionType == POSITION_TYPE_BUY) {
isBuyPosition = true;
} else if (positionType == POSITION_TYPE_SELL) {
isSellPosition = true;
}
}
}
ApplyTrailingStop();
// Check if the cooldown period has elapsed since the last trade
bool cooldownPassed = (currentTime - lastTradeTime) >= cooldownSeconds;
// Check if EMA slope is above the threshold (indicating strong trend)
bool isTrendStrong = MathAbs(emaSlope) > emaSlopeThreshold || MathAbs(priceToEmaDistance) > emaDistanceThreshold;
// Close trade logic when RSI crosses 50
if (isBuyPosition && currentRSI > exitBuyRSI) {
// Close buy position
Close_Position_MN(MagicNumber);
lastTradeTime = currentTime; // Update last trade time
}
if (isSellPosition && currentRSI < exitSellRSI) {
Close_Position_MN(MagicNumber);
lastTradeTime = currentTime; // Update last trade time
}
// If the EMA slope is strong, do not place new trades
if (isTrendStrong) {
Close_Position_MN(MagicNumber);
lastTradeTime = currentTime; // Update last trade time
Print("Strong trend detected (EMA slope), skipping new trade.");
return;
}
// SELL logic (RSI crosses over the overbought level)
if (currentRSI < overboughtLevel - entryRSISellSpread && previousRSIDef >= overboughtLevel && !isSellPosition && !hasPosition && cooldownPassed) {
trade.SetExpertMagicNumber(MagicNumber);
if (trade.Sell(lotSize, _Symbol, 0, 0, "Sell Order")) {
Print("Sell order placed.");
lastTradeTime = currentTime; // Update last trade time
} else {
Print("Error placing sell order: ", GetLastError());
}
}
// BUY logic (RSI crosses below the oversold level)
if (currentRSI > oversoldLevel + entryRSIBuySpread && previousRSIDef <= oversoldLevel && !isBuyPosition && !hasPosition && cooldownPassed) {
trade.SetExpertMagicNumber(MagicNumber);
if (trade.Buy(lotSize, _Symbol, 0, 0, "Buy Order")) {
Print("Buy order placed.");
lastTradeTime = currentTime; // Update last trade time
} else {
Print("Error placing buy order: ", GetLastError());
}
}
previousRSIDef = currentRSI;
}
void OnDeinit(const int reason) {
// Release RSI and EMA handles on deinitialization
if (rsiHandle != INVALID_HANDLE) {
IndicatorRelease(rsiHandle);
Print("RSI handle released.");
}
if (emaHandle != INVALID_HANDLE) {
IndicatorRelease(emaHandle);
Print("EMA handle released.");
}
}
void Close_Position_MN(ulong magicNumber)
{
// Use helper function to close position by magic number
ClosePositionByMagic(trade, _Symbol, (int)magicNumber);
}
void ApplyTrailingStop()
{
Print("Scanning for trailing stop");
// Check if position exists with our magic number
if(!PositionSelectByMagic(_Symbol, MagicNumber))
{
return; // No position with our magic number
}
ulong PositionTicket = PositionGetInteger(POSITION_TICKET);
long trade_type = PositionGetInteger(POSITION_TYPE);
string symbol = _Symbol;
double POINT = SymbolInfoDouble(symbol, SYMBOL_POINT);
int DIGIT = (int) SymbolInfoInteger(symbol, SYMBOL_DIGITS);
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))
{
ModifyPositionByMagic(trade, symbol, MagicNumber,
NormalizeDouble(Bid - POINT * TrailingStop, DIGIT),
PositionGetDouble(POSITION_TP));
}
}
}
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))
{
ModifyPositionByMagic(trade, symbol, MagicNumber,
NormalizeDouble(Ask + POINT * TrailingStop, DIGIT),
PositionGetDouble(POSITION_TP));
}
}
}
}
int TimeHour(datetime when=0){ if(when == 0) when = TimeCurrent();
return when / 3600 % 24;
}
@@ -1,604 +0,0 @@
//+------------------------------------------------------------------+
//| RSIFollowReverseEMACrossOver.mq5 |
//| Copyright 2024, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include <Trade\Trade.mqh>
#include <Trade\PositionInfo.mqh>
#include "../_united/MagicNumberHelpers.mqh"
// Input Parameters
input group "General Settings"
input ENUM_TIMEFRAMES InpTimeframe = PERIOD_H1; // Trading Timeframe
input double InpLotSize = 0.1; // Lot Size
input int InpMagicNumberRSIFollow = 1001; // Magic Number RSI Follow
input int InpMagicNumberRSIReverse = 1002;// Magic Number RSI Reverse
input int InpMagicNumberEMACross = 1003; // Magic Number EMA Cross
input group "Strategy Switches"
input bool InpEnableRSIFollow = true; // Enable RSI Follow Strategy
input bool InpEnableRSIReverse = true; // Enable RSI Reverse Strategy
input bool InpEnableEMACross = true; // Enable EMA Cross Strategy
input bool InpEnableStrategyLock = true; // Enable Strategy Lock
input double InpLockProfitThreshold = 6.0; // Lock Profit Threshold (pips)
input bool InpCloseOppositeTrades = true; // Close Opposite Trades When Profiting
input group "RSI Follow Strategy"
input int InpRSIPeriod = 32; // RSI Period
input int InpRSIOverbought = 78; // RSI Overbought Level
input int InpRSIOversold = 46; // RSI Oversold Level
input int InpRSIExitLevel = 44; // RSI Exit Level
input int InpRSIFollowStartHour = 23; // RSI Follow Start Hour (0-23)
input int InpRSIFollowEndHour = 8; // RSI Follow End Hour (0-23)
input bool InpRSIFollowCloseOutsideHours = false; // Close trades outside trading hours
input group "RSI Reverse Strategy"
input int InpRSIReversePeriod = 59; // RSI Period
input int InpRSIReverseOverbought = 51; // RSI Overbought Level
input int InpRSIReverseOversold = 49; // RSI Oversold Level
input int InpRSIReverseCrossLevel = 53; // RSI Cross Level
input int InpRSIReverseExitLevel = 48; // RSI Exit Level
input int InpRSIReverseStartHour = 7; // RSI Reverse Start Hour (0-23)
input int InpRSIReverseEndHour = 13; // RSI Reverse End Hour (0-23)
input bool InpRSIReverseCloseOutsideHours = false; // Close trades outside trading hours
input int InpRSIReverseCooldownBars = 15; // RSI Reverse Cooldown (bars)
input bool InpRSIReverseCooldownOnLoss = true; // Apply cooldown only on loss
input group "EMA Cross Strategy"
input int InpEMAPeriod = 120; // EMA Period
input int InpEMACrossStartHour = 8; // EMA Cross Start Hour (0-23)
input int InpEMACrossEndHour = 14; // EMA Cross End Hour (0-23)
input bool InpEMACrossCloseOutsideHours = true; // Close trades outside trading hours
input bool InpUseEMADistanceEntry = true; // Use EMA Distance Entry
input double InpEMADistancePips = 160.0; // EMA Distance Threshold (pips)
input int InpEMADistancePeriod = 26; // EMA Distance Period (bars)
// Global Variables
int rsiHandle;
int rsiReverseHandle;
int emaHandle;
bool rsiOverbought = false;
bool rsiOversold = false;
bool rsiReverseOverbought = false;
bool rsiReverseOversold = false;
CTrade trade;
CPositionInfo positionInfo;
bool emaCrossBuySignal = false;
bool emaCrossSellSignal = false;
int emaCrossSignalBar = 0;
datetime lastBarTime = 0;
datetime rsiReverseLastCloseTime = 0;
bool rsiReverseInCooldown = false;
double lastBarRSI = 0; // Store last bar's RSI value
double lastBarRSIReverse = 0; // Store last bar's RSI Reverse value
double lastBarEMA = 0; // Store last bar's EMA value
double lastBarClose = 0; // Store last bar's close value
double lastBarEMAPrev = 0; // Store previous bar's EMA value
double lastBarClosePrev = 0; // Store previous bar's close value
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Initialize indicators
rsiHandle = iRSI(_Symbol, InpTimeframe, InpRSIPeriod, PRICE_CLOSE);
rsiReverseHandle = iRSI(_Symbol, InpTimeframe, InpRSIReversePeriod, PRICE_CLOSE);
emaHandle = iMA(_Symbol, InpTimeframe, InpEMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
if(rsiHandle == INVALID_HANDLE || rsiReverseHandle == INVALID_HANDLE || emaHandle == INVALID_HANDLE)
{
Print("Error creating indicators");
return INIT_FAILED;
}
// Initialize trade settings
trade.SetExpertMagicNumber(InpMagicNumberRSIFollow);
trade.SetMarginMode();
trade.SetTypeFillingBySymbol(_Symbol);
trade.SetDeviationInPoints(10);
// Initialize last bar time
datetime time[];
if(CopyTime(_Symbol, InpTimeframe, 0, 1, time) > 0)
{
lastBarTime = time[0];
}
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Check if new bar has formed |
//+------------------------------------------------------------------+
bool IsNewBar()
{
datetime time[];
if(CopyTime(_Symbol, InpTimeframe, 0, 1, time) > 0)
{
if(time[0] != lastBarTime)
{
lastBarTime = time[0];
return true;
}
}
return false;
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// Release indicator handles
IndicatorRelease(rsiHandle);
IndicatorRelease(rsiReverseHandle);
IndicatorRelease(emaHandle);
}
//+------------------------------------------------------------------+
//| Check if current time is within trading hours |
//+------------------------------------------------------------------+
bool IsWithinTradingHours(int startHour, int endHour)
{
MqlDateTime currentTime;
TimeToStruct(TimeCurrent(), currentTime);
if(startHour <= endHour)
{
return (currentTime.hour >= startHour && currentTime.hour < endHour);
}
else
{
return (currentTime.hour >= startHour || currentTime.hour < endHour);
}
}
//+------------------------------------------------------------------+
//| Check if position exists for given magic number AND symbol |
//+------------------------------------------------------------------+
bool HasPosition(int magic)
{
// Use helper function that verifies BOTH symbol AND magic number for THIS EA
return PositionExistsByMagic(_Symbol, magic);
}
//+------------------------------------------------------------------+
//| Check if any strategy has profitable position |
//+------------------------------------------------------------------+
bool HasProfitablePosition(int excludeMagic)
{
bool hasProfitable = false;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(positionInfo.SelectByIndex(i))
{
if(positionInfo.Magic() != excludeMagic)
{
double profit = positionInfo.Profit();
if(profit > InpLockProfitThreshold * _Point)
{
hasProfitable = true;
// If enabled, close opposite trades
if(InpCloseOppositeTrades)
{
// Check if this is an opposite trade to the excluded magic number
if((excludeMagic == InpMagicNumberRSIFollow && positionInfo.Magic() == InpMagicNumberRSIReverse) ||
(excludeMagic == InpMagicNumberRSIReverse && positionInfo.Magic() == InpMagicNumberRSIFollow) ||
(excludeMagic == InpMagicNumberEMACross && (positionInfo.Magic() == InpMagicNumberRSIReverse || positionInfo.Magic() == InpMagicNumberRSIFollow)) ||
((excludeMagic == InpMagicNumberRSIFollow || excludeMagic == InpMagicNumberRSIReverse) && positionInfo.Magic() == InpMagicNumberEMACross))
{
ClosePosition(positionInfo.Magic());
}
}
}
}
}
}
return hasProfitable;
}
//+------------------------------------------------------------------+
//| Check for RSI Follow Strategy signals |
//+------------------------------------------------------------------+
void CheckRSIFollowStrategy()
{
// Check if within trading hours
if(!IsWithinTradingHours(InpRSIFollowStartHour, InpRSIFollowEndHour))
{
if(InpRSIFollowCloseOutsideHours)
{
if(HasPosition(InpMagicNumberRSIFollow))
{
ClosePosition(InpMagicNumberRSIFollow);
}
}
return;
}
// Check strategy lock
if(InpEnableStrategyLock && HasProfitablePosition(InpMagicNumberRSIFollow))
return;
// Use lastBarRSI instead of copying buffer
if(lastBarRSI > InpRSIOverbought)
rsiOverbought = true;
else if(lastBarRSI < InpRSIOversold)
rsiOversold = true;
// Check for entry signals
if(rsiOverbought && lastBarRSI < InpRSIExitLevel)
{
// Sell signal
if(!HasPosition(InpMagicNumberRSIFollow))
{
trade.SetExpertMagicNumber(InpMagicNumberRSIFollow);
trade.Sell(InpLotSize, _Symbol, 0, 0, 0, "RSI Follow");
}
rsiOverbought = false;
}
else if(rsiOversold && lastBarRSI > InpRSIExitLevel)
{
// Buy signal
if(!HasPosition(InpMagicNumberRSIFollow))
{
trade.SetExpertMagicNumber(InpMagicNumberRSIFollow);
trade.Buy(InpLotSize, _Symbol, 0, 0, 0, "RSI Follow");
}
rsiOversold = false;
}
}
//+------------------------------------------------------------------+
//| Check if RSI Reverse is in cooldown |
//+------------------------------------------------------------------+
bool IsRSIReverseInCooldown()
{
if(InpRSIReverseCooldownBars <= 0)
return false;
if(!rsiReverseInCooldown)
return false;
datetime time[];
if(CopyTime(_Symbol, InpTimeframe, 0, 1, time) > 0)
{
datetime currentBarTime = time[0];
datetime cooldownEndTime = rsiReverseLastCloseTime + InpRSIReverseCooldownBars * PeriodSeconds(InpTimeframe);
if(currentBarTime >= cooldownEndTime)
{
rsiReverseInCooldown = false;
return false;
}
}
return true;
}
//+------------------------------------------------------------------+
//| Check for RSI Reverse Strategy signals |
//+------------------------------------------------------------------+
void CheckRSIReverseStrategy()
{
// Check if within trading hours
if(!IsWithinTradingHours(InpRSIReverseStartHour, InpRSIReverseEndHour))
{
if(InpRSIReverseCloseOutsideHours)
{
if(HasPosition(InpMagicNumberRSIReverse))
{
ClosePosition(InpMagicNumberRSIReverse);
}
}
return;
}
// Check strategy lock
if(InpEnableStrategyLock && HasProfitablePosition(InpMagicNumberRSIReverse))
return;
// Check cooldown
if(IsRSIReverseInCooldown())
return;
// Use lastBarRSIReverse instead of copying buffer
if(lastBarRSIReverse > InpRSIReverseOverbought)
rsiReverseOverbought = true;
else if(lastBarRSIReverse < InpRSIReverseOversold)
rsiReverseOversold = true;
// Check for entry signals
if(rsiReverseOverbought && lastBarRSIReverse < InpRSIReverseCrossLevel)
{
// Sell signal
if(!HasPosition(InpMagicNumberRSIReverse))
{
trade.SetExpertMagicNumber(InpMagicNumberRSIReverse);
trade.Sell(InpLotSize, _Symbol, 0, 0, 0, "RSI Reverse");
}
rsiReverseOverbought = false;
}
else if(rsiReverseOversold && lastBarRSIReverse > InpRSIReverseCrossLevel)
{
// Buy signal
if(!HasPosition(InpMagicNumberRSIReverse))
{
trade.SetExpertMagicNumber(InpMagicNumberRSIReverse);
trade.Buy(InpLotSize, _Symbol, 0, 0, 0, "RSI Reverse");
}
rsiReverseOversold = false;
}
}
//+------------------------------------------------------------------+
//| Check for EMA Cross Strategy signals |
//+------------------------------------------------------------------+
void CheckEMACrossStrategy()
{
// Check if within trading hours
if(!IsWithinTradingHours(InpEMACrossStartHour, InpEMACrossEndHour))
{
if(InpEMACrossCloseOutsideHours)
{
if(HasPosition(InpMagicNumberEMACross))
{
ClosePosition(InpMagicNumberEMACross);
}
}
return;
}
// Check strategy lock
if(InpEnableStrategyLock && HasProfitablePosition(InpMagicNumberEMACross))
return;
// Check for cross signals using stored values
if(lastBarEMAPrev < lastBarClosePrev && lastBarEMA > lastBarClose)
{
// Buy cross signal
emaCrossBuySignal = true;
emaCrossSellSignal = false;
emaCrossSignalBar = 0;
}
else if(lastBarEMAPrev > lastBarClosePrev && lastBarEMA < lastBarClose)
{
// Sell cross signal
emaCrossSellSignal = true;
emaCrossBuySignal = false;
emaCrossSignalBar = 0;
}
// Check for distance entry conditions
if(InpUseEMADistanceEntry)
{
if(emaCrossBuySignal)
{
// Check if price has moved above EMA by the required distance for the required period
bool distanceConditionMet = true;
double emaHistory[], closeHistory[];
ArraySetAsSeries(emaHistory, true);
ArraySetAsSeries(closeHistory, true);
if(CopyBuffer(emaHandle, 0, 0, InpEMADistancePeriod, emaHistory) > 0 &&
CopyClose(_Symbol, InpTimeframe, 0, InpEMADistancePeriod, closeHistory) > 0)
{
for(int i = 0; i < InpEMADistancePeriod; i++)
{
double distance = (closeHistory[i] - emaHistory[i]) / _Point;
if(distance < InpEMADistancePips)
{
distanceConditionMet = false;
break;
}
}
if(distanceConditionMet && !HasPosition(InpMagicNumberEMACross))
{
trade.SetExpertMagicNumber(InpMagicNumberEMACross);
trade.Buy(InpLotSize, _Symbol, 0, 0, 0, "EMA Cross Distance");
emaCrossBuySignal = false;
}
}
}
else if(emaCrossSellSignal)
{
// Check if price has moved below EMA by the required distance for the required period
bool distanceConditionMet = true;
double emaHistory[], closeHistory[];
ArraySetAsSeries(emaHistory, true);
ArraySetAsSeries(closeHistory, true);
if(CopyBuffer(emaHandle, 0, 0, InpEMADistancePeriod, emaHistory) > 0 &&
CopyClose(_Symbol, InpTimeframe, 0, InpEMADistancePeriod, closeHistory) > 0)
{
for(int i = 0; i < InpEMADistancePeriod; i++)
{
double distance = (emaHistory[i] - closeHistory[i]) / _Point;
if(distance < InpEMADistancePips)
{
distanceConditionMet = false;
break;
}
}
if(distanceConditionMet && !HasPosition(InpMagicNumberEMACross))
{
trade.SetExpertMagicNumber(InpMagicNumberEMACross);
trade.Sell(InpLotSize, _Symbol, 0, 0, 0, "EMA Cross Distance");
emaCrossSellSignal = false;
}
}
}
}
else
{
// Original cross entry logic using stored values
if(lastBarEMAPrev < lastBarClosePrev && lastBarEMA > lastBarClose)
{
// Buy signal
if(!HasPosition(InpMagicNumberEMACross))
{
trade.SetExpertMagicNumber(InpMagicNumberEMACross);
trade.Buy(InpLotSize, _Symbol, 0, 0, 0, "EMA Cross");
}
}
else if(lastBarEMAPrev > lastBarClosePrev && lastBarEMA < lastBarClose)
{
// Sell signal
if(!HasPosition(InpMagicNumberEMACross))
{
trade.SetExpertMagicNumber(InpMagicNumberEMACross);
trade.Sell(InpLotSize, _Symbol, 0, 0, 0, "EMA Cross");
}
}
}
// Increment signal bar counter
if(emaCrossBuySignal || emaCrossSellSignal)
{
emaCrossSignalBar++;
// Reset signals if they're too old (optional, can be removed if not needed)
if(emaCrossSignalBar > InpEMADistancePeriod * 2)
{
emaCrossBuySignal = false;
emaCrossSellSignal = false;
}
}
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// Only process on new bar
if(!IsNewBar())
return;
// Get indicator values for the new bar
double rsi[], rsiReverse[], ema[], close[];
ArraySetAsSeries(rsi, true);
ArraySetAsSeries(rsiReverse, true);
ArraySetAsSeries(ema, true);
ArraySetAsSeries(close, true);
// Store previous values
lastBarEMAPrev = lastBarEMA;
lastBarClosePrev = lastBarClose;
// Get new values
if(CopyBuffer(rsiHandle, 0, 0, 1, rsi) > 0)
lastBarRSI = rsi[0];
if(CopyBuffer(rsiReverseHandle, 0, 0, 1, rsiReverse) > 0)
lastBarRSIReverse = rsiReverse[0];
if(CopyBuffer(emaHandle, 0, 0, 1, ema) > 0)
lastBarEMA = ema[0];
if(CopyClose(_Symbol, InpTimeframe, 0, 1, close) > 0)
lastBarClose = close[0];
// Check for new signals
if(InpEnableRSIFollow)
CheckRSIFollowStrategy();
if(InpEnableRSIReverse)
CheckRSIReverseStrategy();
if(InpEnableEMACross)
CheckEMACrossStrategy();
// Check for exit conditions
CheckExitConditions();
}
//+------------------------------------------------------------------+
//| Check exit conditions for all strategies |
//+------------------------------------------------------------------+
void CheckExitConditions()
{
if(InpEnableRSIFollow)
{
// Check RSI Follow exit conditions
if(HasPosition(InpMagicNumberRSIFollow))
{
if((positionInfo.PositionType() == POSITION_TYPE_BUY && lastBarRSI < InpRSIExitLevel) ||
(positionInfo.PositionType() == POSITION_TYPE_SELL && lastBarRSI > InpRSIExitLevel))
{
ClosePosition(InpMagicNumberRSIFollow);
}
}
}
if(InpEnableRSIReverse)
{
// Check RSI Reverse exit conditions
if(HasPosition(InpMagicNumberRSIReverse))
{
if((positionInfo.PositionType() == POSITION_TYPE_BUY && lastBarRSIReverse < InpRSIReverseExitLevel) ||
(positionInfo.PositionType() == POSITION_TYPE_SELL && lastBarRSIReverse > InpRSIReverseExitLevel))
{
ClosePosition(InpMagicNumberRSIReverse);
}
}
}
if(InpEnableEMACross)
{
// Check EMA Cross exit conditions using stored values
if(HasPosition(InpMagicNumberEMACross))
{
if((positionInfo.PositionType() == POSITION_TYPE_BUY && lastBarEMA > lastBarClose) ||
(positionInfo.PositionType() == POSITION_TYPE_SELL && lastBarEMA < lastBarClose))
{
ClosePosition(InpMagicNumberEMACross);
}
}
}
}
//+------------------------------------------------------------------+
//| Close position by magic number |
//+------------------------------------------------------------------+
void ClosePosition(int magic)
{
// 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))
{
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))
{
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
double profit = PositionGetDouble(POSITION_PROFIT);
if(!InpRSIReverseCooldownOnLoss || profit < 0)
{
rsiReverseInCooldown = true;
}
}
}
}
// Close the position using helper function
ClosePositionByMagic(trade, _Symbol, magic);
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

@@ -1,539 +0,0 @@
//+------------------------------------------------------------------+
//| SimpleRSIReversalAUDUSD.mq5 |
//| Copyright 2024, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
// Include trade class
#include <Trade\Trade.mqh>
// Input parameters
input int RSIPeriod = 28; // RSI period
input double OverboughtLevel = 60; // Overbought level
input double OversoldLevel = 8; // Oversold level
input int TakeProfitPips = 175; // Take profit in pips
input int StopLossPips = 5; // Stop loss in pips
input double MaxLotSize = 0.1; // Maximum lot size
input int MaxSpread = 1000; // Maximum allowed spread in pips
input int MaxDuration = 270; // Maximum trade duration in hours
input bool UseStopLoss = false; // Use stop loss
input bool UseTakeProfit = false; // Use take profit
input bool UseRSIExit = true; // Use RSI for exit
input double RSIExitLevel = 55; // RSI level to exit (50 = neutral)
input bool CloseOutsideSession = false; // Close trades outside Asian session
input color PanelBackground = clrBlack; // Panel background color
input color PanelText = clrWhite; // Panel text color
input int PanelX = 10; // Panel X position
input int PanelY = 20; // Panel Y position
// Global variables
CTrade trade;
int rsiHandle;
bool isPositionOpen = false;
double positionOpenPrice = 0;
datetime positionOpenTime = 0;
ENUM_POSITION_TYPE lastPositionType = POSITION_TYPE_BUY;
bool sessionCloseAttempted = false; // Track if we've attempted to close positions for current session
// RSI crossover variables
double rsiCurrent = 0;
double rsiPrevious = 0;
double rsiPrevious2 = 0;
bool rsiCrossedOverbought = false;
bool rsiCrossedOversold = false;
bool rsiCrossedExitLevel = false;
// Panel objects
string panelName = "RSIPanel";
int panelWidth = 200;
int panelHeight = 200;
int labelHeight = 20;
int labelSpacing = 5;
// Session times (UTC)
const int AsianSessionStart = 0; // 00:00 UTC
const int AsianSessionEnd = 8; // 08:00 UTC
//+------------------------------------------------------------------+
//| Create panel |
//+------------------------------------------------------------------+
void CreatePanel()
{
// Create panel background
ObjectCreate(0, panelName, OBJ_RECTANGLE_LABEL, 0, 0, 0);
ObjectSetInteger(0, panelName, OBJPROP_XDISTANCE, PanelX);
ObjectSetInteger(0, panelName, OBJPROP_YDISTANCE, PanelY);
ObjectSetInteger(0, panelName, OBJPROP_XSIZE, panelWidth);
ObjectSetInteger(0, panelName, OBJPROP_YSIZE, panelHeight);
ObjectSetInteger(0, panelName, OBJPROP_BGCOLOR, PanelBackground);
ObjectSetInteger(0, panelName, OBJPROP_BORDER_TYPE, BORDER_FLAT);
ObjectSetInteger(0, panelName, OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(0, panelName, OBJPROP_COLOR, PanelText);
ObjectSetInteger(0, panelName, OBJPROP_STYLE, STYLE_SOLID);
ObjectSetInteger(0, panelName, OBJPROP_WIDTH, 1);
ObjectSetInteger(0, panelName, OBJPROP_BACK, false);
ObjectSetInteger(0, panelName, OBJPROP_SELECTABLE, false);
ObjectSetInteger(0, panelName, OBJPROP_SELECTED, false);
ObjectSetInteger(0, panelName, OBJPROP_HIDDEN, true);
ObjectSetInteger(0, panelName, OBJPROP_ZORDER, 0);
// Create title label
ObjectCreate(0, panelName + "Title", OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(0, panelName + "Title", OBJPROP_XDISTANCE, PanelX + 5);
ObjectSetInteger(0, panelName + "Title", OBJPROP_YDISTANCE, PanelY + 5);
ObjectSetInteger(0, panelName + "Title", OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetString(0, panelName + "Title", OBJPROP_TEXT, "RSI Reversal");
ObjectSetInteger(0, panelName + "Title", OBJPROP_COLOR, PanelText);
ObjectSetInteger(0, panelName + "Title", OBJPROP_FONTSIZE, 10);
// Create score labels
CreateScoreLabel("RSI", "RSI: ", 0);
CreateScoreLabel("Position", "Position: ", 1);
CreateScoreLabel("Spread", "Spread: ", 2);
CreateScoreLabel("Session", "Session: ", 3);
CreateScoreLabel("SL", "Stop Loss: ", 4);
CreateScoreLabel("TP", "Take Profit: ", 5);
CreateScoreLabel("Cross", "Cross: ", 6);
}
//+------------------------------------------------------------------+
//| Create score label |
//+------------------------------------------------------------------+
void CreateScoreLabel(string name, string text, int index)
{
ObjectCreate(0, panelName + name, OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(0, panelName + name, OBJPROP_XDISTANCE, PanelX + 5);
ObjectSetInteger(0, panelName + name, OBJPROP_YDISTANCE, PanelY + 30 + index * (labelHeight + labelSpacing));
ObjectSetInteger(0, panelName + name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetString(0, panelName + name, OBJPROP_TEXT, text);
ObjectSetInteger(0, panelName + name, OBJPROP_COLOR, PanelText);
ObjectSetInteger(0, panelName + name, OBJPROP_FONTSIZE, 8);
}
//+------------------------------------------------------------------+
//| Update panel values |
//+------------------------------------------------------------------+
void UpdatePanel(double rsi, string position, int spread, string session, double sl, double tp, string crossInfo)
{
ObjectSetString(0, panelName + "RSI", OBJPROP_TEXT, "RSI: " + DoubleToString(rsi, 2));
ObjectSetString(0, panelName + "Position", OBJPROP_TEXT, "Position: " + position);
ObjectSetString(0, panelName + "Spread", OBJPROP_TEXT, "Spread: " + IntegerToString(spread) + " pips");
ObjectSetString(0, panelName + "Session", OBJPROP_TEXT, "Session: " + session);
ObjectSetString(0, panelName + "SL", OBJPROP_TEXT, "Stop Loss: " + IntegerToString(StopLossPips) + " pips");
ObjectSetString(0, panelName + "TP", OBJPROP_TEXT, "Take Profit: " + IntegerToString(TakeProfitPips) + " pips");
ObjectSetString(0, panelName + "Cross", OBJPROP_TEXT, "Cross: " + crossInfo);
}
//+------------------------------------------------------------------+
//| Check if current time is in Asian session |
//+------------------------------------------------------------------+
bool IsAsianSession()
{
datetime currentTime = TimeCurrent();
MqlDateTime timeStruct;
TimeToStruct(currentTime, timeStruct);
return (timeStruct.hour >= AsianSessionStart && timeStruct.hour < AsianSessionEnd);
}
//+------------------------------------------------------------------+
//| Get current session name |
//+------------------------------------------------------------------+
string GetCurrentSession()
{
datetime currentTime = TimeCurrent();
MqlDateTime timeStruct;
TimeToStruct(currentTime, timeStruct);
if(timeStruct.hour >= AsianSessionStart && timeStruct.hour < AsianSessionEnd)
return "Asian";
else if(timeStruct.hour >= 8 && timeStruct.hour < 16)
return "London";
else if(timeStruct.hour >= 13 && timeStruct.hour < 21)
return "New York";
else
return "Other";
}
//+------------------------------------------------------------------+
//| Check if trading is allowed |
//+------------------------------------------------------------------+
bool IsTradingAllowed()
{
// Check if market is open
if(!SymbolInfoInteger(_Symbol, SYMBOL_TRADE_MODE) == SYMBOL_TRADE_MODE_FULL)
{
return false;
}
// Check if we have enough money
if(AccountInfoDouble(ACCOUNT_MARGIN_FREE) <= 0)
{
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| Check RSI crossover conditions |
//+------------------------------------------------------------------+
void CheckRSICrossover()
{
// Reset crossover flags
rsiCrossedOverbought = false;
rsiCrossedOversold = false;
rsiCrossedExitLevel = false;
// Check for overbought crossover (RSI crosses above overbought level)
if(rsiPrevious < OverboughtLevel && rsiCurrent >= OverboughtLevel)
{
rsiCrossedOverbought = true;
}
// Check for oversold crossover (RSI crosses below oversold level)
if(rsiPrevious > OversoldLevel && rsiCurrent <= OversoldLevel)
{
rsiCrossedOversold = true;
}
// Check for exit level crossover
if(rsiPrevious < RSIExitLevel && rsiCurrent >= RSIExitLevel)
{
rsiCrossedExitLevel = true;
}
else if(rsiPrevious > RSIExitLevel && rsiCurrent <= RSIExitLevel)
{
rsiCrossedExitLevel = true;
}
}
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Initialize RSI indicator
rsiHandle = iRSI(_Symbol, PERIOD_M15, RSIPeriod, PRICE_CLOSE);
if(rsiHandle == INVALID_HANDLE)
{
return(INIT_FAILED);
}
// Wait a bit for the indicator to be ready
Sleep(100);
// Initialize RSI values with retry logic
double rsi[];
ArraySetAsSeries(rsi, true);
int retryCount = 0;
bool rsiInitialized = false;
while(retryCount < 10 && !rsiInitialized)
{
int copied = CopyBuffer(rsiHandle, 0, 0, 3, rsi);
if(copied >= 3)
{
rsiCurrent = rsi[0];
rsiPrevious = rsi[1];
rsiPrevious2 = rsi[2];
rsiInitialized = true;
}
else
{
retryCount++;
Sleep(100);
}
}
if(!rsiInitialized)
{
// Don't fail initialization, just set default values
rsiCurrent = 50.0;
rsiPrevious = 50.0;
rsiPrevious2 = 50.0;
}
// Create panel
CreatePanel();
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// Release indicator handles
IndicatorRelease(rsiHandle);
// Remove panel objects
ObjectsDeleteAll(0, panelName);
}
//+------------------------------------------------------------------+
//| Close all trades for the current symbol |
//+------------------------------------------------------------------+
bool CloseAllTrades(string reason = "")
{
bool allClosed = true;
int totalPositions = PositionsTotal();
if(totalPositions == 0)
return true;
// Check if there are any positions with our magic number
bool hasOurPositions = false;
for(int i = 0; i < totalPositions; i++)
{
if(PositionGetSymbol(i) == _Symbol && PositionGetInteger(POSITION_MAGIC) == 123456)
{
hasOurPositions = true;
break;
}
}
for(int i = totalPositions - 1; i >= 0; i--)
{
if(PositionGetSymbol(i) == _Symbol)
{
// Try to close position with retry logic
int retryCount = 0;
bool positionClosed = false;
while(retryCount < 3 && !positionClosed)
{
if(trade.PositionClose(_Symbol))
{
isPositionOpen = false;
positionClosed = true;
}
else
{
int error = GetLastError();
// If error is 4756 (Trade disabled), wait longer before retry
if(error == 4756)
{
Sleep(5000); // Wait 5 seconds before retry
retryCount++;
}
else
{
// For other errors, break the loop
break;
}
}
}
if(!positionClosed)
{
allClosed = false;
}
}
}
return allClosed;
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// Check if trading is allowed
if(!IsTradingAllowed())
{
return;
}
// Check if we're in Asian session
if(!IsAsianSession())
{
// Close all positions if outside Asian session and CloseOutsideSession is true
if(CloseOutsideSession && !sessionCloseAttempted)
{
CloseAllTrades("Outside Asian session");
sessionCloseAttempted = true;
}
return;
}
else
{
// Reset the session close attempt flag when we enter Asian session
sessionCloseAttempted = false;
}
// Get current spread
double spread = SymbolInfoDouble(_Symbol, SYMBOL_ASK) - SymbolInfoDouble(_Symbol, SYMBOL_BID);
int spreadInPips = (int)(spread / _Point);
// Check if spread is too high
if(spreadInPips > MaxSpread)
{
return;
}
// Get RSI values from bar data
double rsi[];
ArraySetAsSeries(rsi, true);
int copied = CopyBuffer(rsiHandle, 0, 0, 3, rsi);
if(copied < 3)
{
return;
}
// Update RSI values
rsiPrevious2 = rsiPrevious;
rsiPrevious = rsiCurrent;
rsiCurrent = rsi[0];
// Validate RSI values
if(rsiCurrent == 0 || rsiPrevious == 0)
{
return;
}
// Check for RSI crossovers
CheckRSICrossover();
// Get current prices
double currentBid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double currentAsk = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
// Get position status
string positionStatus = "None";
for(int i = 0; i < PositionsTotal(); i++)
{
if(PositionGetSymbol(i) == _Symbol)
{
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
positionStatus = (posType == POSITION_TYPE_BUY) ? "Long" : "Short";
break;
}
}
// Calculate stop loss and take profit levels
double sl = 0;
double tp = 0;
// Prepare crossover info for panel
string crossInfo = "None";
if(rsiCrossedOverbought) crossInfo = "Overbought";
else if(rsiCrossedOversold) crossInfo = "Oversold";
else if(rsiCrossedExitLevel) crossInfo = "Exit";
// Update panel
UpdatePanel(rsiCurrent, positionStatus, spreadInPips, GetCurrentSession(), sl, tp, crossInfo);
// Check for open position
bool hasOpenPosition = false;
for(int i = 0; i < PositionsTotal(); i++)
{
if(PositionGetSymbol(i) == _Symbol)
{
hasOpenPosition = true;
// Get position details
double positionProfit = PositionGetDouble(POSITION_PROFIT);
double positionVolume = PositionGetDouble(POSITION_VOLUME);
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
// Check for RSI exit if enabled
if(UseRSIExit && rsiCrossedExitLevel)
{
bool shouldExit = false;
// For long positions, exit when RSI crosses above exit level
if(posType == POSITION_TYPE_BUY && rsiCurrent >= RSIExitLevel && rsiPrevious < RSIExitLevel)
{
shouldExit = true;
}
// For short positions, exit when RSI crosses below exit level
else if(posType == POSITION_TYPE_SELL && rsiCurrent <= RSIExitLevel && rsiPrevious > RSIExitLevel)
{
shouldExit = true;
}
if(shouldExit)
{
CloseAllTrades("RSI Exit Crossover");
return;
}
}
// Check for timeout
if(TimeCurrent() - positionOpenTime > MaxDuration * 3600)
{
CloseAllTrades("Timeout");
return;
}
break;
}
}
// If no position is open, look for entry signals based on RSI crossover
if(!hasOpenPosition)
{
// Place buy order if RSI crosses below oversold level (oversold crossover)
if(rsiCrossedOversold)
{
double sl = UseStopLoss ? currentBid - StopLossPips * _Point : 0;
double tp = UseTakeProfit ? currentBid + TakeProfitPips * _Point : 0;
if(UseStopLoss && sl >= currentBid)
return;
if(UseTakeProfit && tp <= currentBid)
return;
// Set trade parameters
trade.SetDeviationInPoints(3);
trade.SetTypeFilling(ORDER_FILLING_IOC);
trade.SetExpertMagicNumber(123456);
// Place buy order using CTrade
if(trade.Buy(MaxLotSize, _Symbol, currentAsk, sl, tp, "RSI Oversold Crossover Buy"))
{
isPositionOpen = true;
positionOpenPrice = currentAsk;
positionOpenTime = TimeCurrent();
lastPositionType = POSITION_TYPE_BUY;
}
}
// Place sell order if RSI crosses above overbought level (overbought crossover)
else if(rsiCrossedOverbought)
{
double sl = UseStopLoss ? currentAsk + StopLossPips * _Point : 0;
double tp = UseTakeProfit ? currentAsk - TakeProfitPips * _Point : 0;
if(UseStopLoss && sl <= currentAsk)
return;
if(UseTakeProfit && tp >= currentAsk)
return;
// Set trade parameters
trade.SetDeviationInPoints(3);
trade.SetTypeFilling(ORDER_FILLING_IOC);
trade.SetExpertMagicNumber(123456);
// Place sell order using CTrade
if(trade.Sell(MaxLotSize, _Symbol, currentBid, sl, tp, "RSI Overbought Crossover Sell"))
{
isPositionOpen = true;
positionOpenPrice = currentBid;
positionOpenTime = TimeCurrent();
lastPositionType = POSITION_TYPE_SELL;
}
}
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 250 KiB

@@ -1,581 +0,0 @@
//+------------------------------------------------------------------+
//| RSIScalping.mq5 |
//| Copyright 2025, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.01"
#include <Trade\Trade.mqh>
#include "../_united/MagicNumberHelpers.mqh"
//--- Input parameters
input ENUM_TIMEFRAMES TimeFrame = PERIOD_H1; // Timeframe for Analysis
input int RSI_Period = 14; // RSI Period
input ENUM_APPLIED_PRICE RSI_Applied_Price = PRICE_CLOSE; // RSI Applied Price
input double RSI_Overbought = 90; // RSI Overbought Level
input double RSI_Oversold = 73; // RSI Oversold Level
input double RSI_Target_Buy = 88; // RSI Target for Buy Exit
input double RSI_Target_Sell = 48; // RSI Target for Sell Exit
input int BarsToWait = 6; // Bars to wait when RSI goes against position
input double LotSize = 0.1; // Lot Size
input int MagicNumber = 123459123; // Magic Number
input int Slippage = 3; // Slippage in points
input group "=== Reversal escape (intrabar, multi-signal) ==="
input bool UseReversalEscape = true; // run while in position every tick
input int ReversalATRPeriod = 14; // ATR lookback on signal timeframe
input double ReversalAdverseAtrMult = 5.25; // close if price vs entry >= this * ATR
input int ReversalSignsRequired = 2; // how many independent signs must align
input double ReversalRsiVelocity = 16.0; // RSI points drop (long) / rise (short) vs prior buffer
input double ReversalBodyAtrMult = 5.1; // last closed bar body >= this * ATR counts as one sign
input group "=== Trailing stop ==="
input bool UseTrailingStop = true; // move SL behind bid/ask while in profit
input double TrailingStopDistancePoints = 120.0; // SL distance from bid/ask (points)
input double TrailingActivationPoints = 0.0; // min profit before trailing (0 = same as distance)
//--- Global variables
CTrade trade;
int rsi_handle;
double rsi_buffer[];
double rsi_prev, rsi_current, rsi_two_bars_ago;
bool position_open = false;
int position_ticket = 0;
ENUM_POSITION_TYPE current_position_type = POSITION_TYPE_BUY;
datetime last_bar_time = 0;
bool rsi_against_position = false;
int bars_against_count = 0;
void ResetPositionTracking();
void SyncTrackedPosition();
double ATRPriceOnTF(const int period);
int CountReversalEscapeSigns(const ENUM_POSITION_TYPE ptype, const double atr);
void TryReversalEscape();
void ApplyTrailingStop();
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Initialize RSI indicator
rsi_handle = iRSI(_Symbol, TimeFrame, RSI_Period, RSI_Applied_Price);
if(rsi_handle == INVALID_HANDLE)
{
return(INIT_FAILED);
}
// Initialize trade object
trade.SetExpertMagicNumber(MagicNumber);
trade.SetDeviationInPoints(Slippage);
trade.SetTypeFilling(ORDER_FILLING_FOK);
// Allocate arrays
ArraySetAsSeries(rsi_buffer, true);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if(rsi_handle != INVALID_HANDLE)
IndicatorRelease(rsi_handle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// Check if we have enough bars
if(Bars(_Symbol, TimeFrame) < RSI_Period + 2)
{
return;
}
// Check if this is a new bar
datetime current_bar_time = iTime(_Symbol, TimeFrame, 0);
bool is_new_bar = (current_bar_time != last_bar_time);
bool in_position = position_open || PositionExistsByMagic(_Symbol, (ulong)MagicNumber);
// While flat, process only on new bars. While in position, allow intrabar reversal escape checks.
if(!in_position && !is_new_bar)
{
return;
}
// Update RSI values
if(!UpdateRSI())
{
return;
}
if(in_position && UseReversalEscape)
{
TryReversalEscape();
}
if(in_position && UseTrailingStop)
ApplyTrailingStop();
if(!is_new_bar)
{
return;
}
last_bar_time = current_bar_time;
// Keep local tracking aligned with actual terminal positions for this symbol/magic.
SyncTrackedPosition();
// Check for existing position
CheckExistingPosition();
// Check for new entry signals - only if no position exists for THIS EA (magic number) on THIS symbol
if(!position_open && !PositionExistsByMagic(_Symbol, (ulong)MagicNumber))
{
CheckEntrySignals();
}
}
//+------------------------------------------------------------------+
//| Update RSI values |
//+------------------------------------------------------------------+
bool UpdateRSI()
{
if(CopyBuffer(rsi_handle, 0, 0, 3, rsi_buffer) < 3)
{
return false;
}
rsi_current = rsi_buffer[0]; // Current bar
rsi_prev = rsi_buffer[1]; // Previous bar
rsi_two_bars_ago = rsi_buffer[2]; // Two bars ago
return true;
}
//+------------------------------------------------------------------+
//| Wilder ATR in price units (signal timeframe) |
//+------------------------------------------------------------------+
double ATRPriceOnTF(const int period)
{
if(period < 1)
return 0.0;
MqlRates rates[];
const int need = period + 2;
if(CopyRates(_Symbol, TimeFrame, 0, need, rates) < need)
return 0.0;
ArraySetAsSeries(rates, true);
double sum = 0.0;
for(int i = 1; i <= period; i++)
{
const double hl = rates[i].high - rates[i].low;
const double hc = MathAbs(rates[i].high - rates[i + 1].close);
const double lc = MathAbs(rates[i].low - rates[i + 1].close);
sum += MathMax(hl, MathMax(hc, lc));
}
return sum / (double)period;
}
//+------------------------------------------------------------------+
//| Independent adverse signs (need ReversalSignsRequired to exit) |
//+------------------------------------------------------------------+
int CountReversalEscapeSigns(const ENUM_POSITION_TYPE ptype, const double atr)
{
if(atr <= 0.0)
return 0;
const double entry = PositionGetDouble(POSITION_PRICE_OPEN);
const double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
const double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
int signs = 0;
if(ptype == POSITION_TYPE_BUY)
{
if(entry - bid >= ReversalAdverseAtrMult * atr)
signs++;
if(rsi_prev - rsi_current >= ReversalRsiVelocity)
signs++;
}
else if(ptype == POSITION_TYPE_SELL)
{
if(ask - entry >= ReversalAdverseAtrMult * atr)
signs++;
if(rsi_current - rsi_prev >= ReversalRsiVelocity)
signs++;
}
else
{
return 0;
}
MqlRates rates[];
if(CopyRates(_Symbol, TimeFrame, 0, 4, rates) >= 4)
{
ArraySetAsSeries(rates, true);
const double body = MathAbs(rates[1].close - rates[1].open);
if(body >= ReversalBodyAtrMult * atr)
{
if(ptype == POSITION_TYPE_BUY && rates[1].close < rates[1].open)
signs++;
else if(ptype == POSITION_TYPE_SELL && rates[1].close > rates[1].open)
signs++;
}
if(ptype == POSITION_TYPE_BUY)
{
if(rates[1].close < rates[2].close && rates[2].close < rates[3].close)
signs++;
}
else
{
if(rates[1].close > rates[2].close && rates[2].close > rates[3].close)
signs++;
}
}
return signs;
}
//+------------------------------------------------------------------+
//| Cut losers fast on violent reversals (evaluated every tick) |
//+------------------------------------------------------------------+
void TryReversalEscape()
{
ulong live_ticket = GetPositionTicketByMagic(_Symbol, (ulong)MagicNumber);
if(live_ticket == 0)
return;
if(!PositionSelectByTicketSymbolAndMagic(live_ticket, _Symbol, (ulong)MagicNumber))
return;
const ENUM_POSITION_TYPE ptype = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
const double atr = ATRPriceOnTF(ReversalATRPeriod);
if(atr <= 0.0)
return;
const int signs = CountReversalEscapeSigns(ptype, atr);
if(signs < ReversalSignsRequired)
return;
ClosePosition();
Print("RSIScalpingBTCUSD: reversal escape signs=", signs, " need=", ReversalSignsRequired,
" ATR=", DoubleToString(atr, (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS)));
}
//+------------------------------------------------------------------+
//| Trail SL behind favorable price (every tick when enabled) |
//+------------------------------------------------------------------+
void ApplyTrailingStop()
{
if(TrailingStopDistancePoints <= 0.0)
return;
if(!PositionSelectByMagic(_Symbol, (ulong)MagicNumber))
return;
const double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
if(point <= 0.0)
return;
const int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
const double trail_dist = TrailingStopDistancePoints * point;
const double activation_pts = (TrailingActivationPoints > 0.0)
? TrailingActivationPoints
: TrailingStopDistancePoints;
const double activation = activation_pts * point;
const long stops_level = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
const double min_dist = (double)stops_level * point;
const ENUM_POSITION_TYPE ptype = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
const double entry = PositionGetDouble(POSITION_PRICE_OPEN);
const double cur_sl = PositionGetDouble(POSITION_SL);
const double cur_tp = PositionGetDouble(POSITION_TP);
if(ptype == POSITION_TYPE_BUY)
{
const double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
if(bid - entry <= activation)
return;
double new_sl = NormalizeDouble(bid - trail_dist, digits);
if(min_dist > 0.0 && bid - new_sl < min_dist)
new_sl = NormalizeDouble(bid - min_dist, digits);
if(new_sl >= bid || new_sl <= 0.0)
return;
if(cur_sl > 0.0 && new_sl <= cur_sl)
return;
ModifyPositionByMagic(trade, _Symbol, (ulong)MagicNumber, new_sl, cur_tp);
}
else if(ptype == POSITION_TYPE_SELL)
{
const double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
if(entry - ask <= activation)
return;
double new_sl = NormalizeDouble(ask + trail_dist, digits);
if(min_dist > 0.0 && new_sl - ask < min_dist)
new_sl = NormalizeDouble(ask + min_dist, digits);
if(new_sl <= ask || new_sl <= 0.0)
return;
if(cur_sl > 0.0 && new_sl >= cur_sl)
return;
ModifyPositionByMagic(trade, _Symbol, (ulong)MagicNumber, new_sl, cur_tp);
}
}
//+------------------------------------------------------------------+
//| Reset local position tracking |
//+------------------------------------------------------------------+
void ResetPositionTracking()
{
position_open = false;
position_ticket = 0;
rsi_against_position = false;
bars_against_count = 0;
}
//+------------------------------------------------------------------+
//| Sync local state with real position in terminal |
//+------------------------------------------------------------------+
void SyncTrackedPosition()
{
ulong live_ticket = GetPositionTicketByMagic(_Symbol, (ulong)MagicNumber);
if(live_ticket == 0)
{
ResetPositionTracking();
return;
}
// If we were not tracking (or ticket changed), start tracking the live position.
if(!position_open || position_ticket != (int)live_ticket)
{
if(PositionSelectByTicketSymbolAndMagic(live_ticket, _Symbol, (ulong)MagicNumber))
{
position_open = true;
position_ticket = (int)live_ticket;
current_position_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
rsi_against_position = false;
bars_against_count = 0;
}
return;
}
}
//+------------------------------------------------------------------+
//| Check existing position for exit conditions |
//+------------------------------------------------------------------+
void CheckExistingPosition()
{
if(!position_open)
{
return;
}
// Check if position still exists with correct magic number AND symbol for THIS EA
if(!PositionSelectByTicketSymbolAndMagic(position_ticket, _Symbol, (ulong)MagicNumber))
{
ResetPositionTracking();
return;
}
// Exit conditions based on RSI target
if(current_position_type == POSITION_TYPE_BUY)
{
// Check if RSI is against the position (below oversold)
if(rsi_current < RSI_Oversold)
{
if(!rsi_against_position)
{
rsi_against_position = true;
bars_against_count = 1;
}
else
{
bars_against_count++;
}
// Close position if RSI has been against for Y bars
if(bars_against_count >= BarsToWait)
{
ClosePosition();
return;
}
}
else
{
// RSI is no longer against the position, reset counter
if(rsi_against_position)
{
rsi_against_position = false;
bars_against_count = 0;
}
// Exit long position when RSI reaches buy target
if(rsi_current >= RSI_Target_Buy)
{
ClosePosition();
}
}
}
else if(current_position_type == POSITION_TYPE_SELL)
{
// Check if RSI is against the position (above overbought)
if(rsi_current > RSI_Overbought)
{
if(!rsi_against_position)
{
rsi_against_position = true;
bars_against_count = 1;
}
else
{
bars_against_count++;
}
// Close position if RSI has been against for Y bars
if(bars_against_count >= BarsToWait)
{
ClosePosition();
return;
}
}
else
{
// RSI is no longer against the position, reset counter
if(rsi_against_position)
{
rsi_against_position = false;
bars_against_count = 0;
}
// Exit short position when RSI reaches sell target
if(rsi_current <= RSI_Target_Sell)
{
ClosePosition();
}
}
}
}
//+------------------------------------------------------------------+
//| Check for entry signals |
//+------------------------------------------------------------------+
void CheckEntrySignals()
{
// Buy signal: RSI crosses from oversold to above oversold (checking the actual crossover)
if(rsi_two_bars_ago <= RSI_Oversold && rsi_prev > RSI_Oversold)
{
OpenBuyPosition();
}
// Sell signal: RSI crosses from overbought to below overbought (checking the actual crossover)
if(rsi_two_bars_ago >= RSI_Overbought && rsi_prev < RSI_Overbought)
{
OpenSellPosition();
}
}
//+------------------------------------------------------------------+
//| Open buy position |
//+------------------------------------------------------------------+
void OpenBuyPosition()
{
// Verify no position exists for THIS EA (magic number) on THIS symbol before opening
if(PositionExistsByMagic(_Symbol, (ulong)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"))
{
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, (ulong)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");
}
}
}
}
//+------------------------------------------------------------------+
//| Open sell position |
//+------------------------------------------------------------------+
void OpenSellPosition()
{
// Verify no position exists for THIS EA (magic number) on THIS symbol before opening
if(PositionExistsByMagic(_Symbol, (ulong)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"))
{
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, (ulong)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");
}
}
}
}
//+------------------------------------------------------------------+
//| Close current position |
//+------------------------------------------------------------------+
void ClosePosition()
{
bool position_exists_before_close = PositionExistsByMagic(_Symbol, (ulong)MagicNumber);
if(!position_exists_before_close)
{
ResetPositionTracking();
return;
}
// Close position using helper that verifies symbol AND magic number for THIS EA
if(ClosePositionByMagic(trade, _Symbol, (ulong)MagicNumber))
{
ResetPositionTracking();
}
else
{
// Keep tracking when close fails (e.g. market closed); retry on next bar.
if(!PositionExistsByMagic(_Symbol, (ulong)MagicNumber))
{
ResetPositionTracking();
}
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

@@ -1,34 +0,0 @@
; RSIScalpingXAUUSD-trailing — matches main.mq5 v1.06 default inputs
; saved on 2026.05.01 22:32:43
; MT5 Strategy Tester: Inputs → Load
;
TimeFrame=16385||15||0||16385||N
RSI_Period=14||14||1||140||N
RSI_Applied_Price=1||1||0||7||N
RSI_Overbought=71.0||0||2||100||N
RSI_Oversold=57.0||0||2||100||N
UseEntrySlopeFilter=false||false||0||true||N
EntryMinSlopePerBar=1.0||1.0||0.100000||10.000000||N
RSI_Target_Buy=80.0||0||2||100||N
RSI_Target_Sell=57.0||0||2||100||N
BarsToWait=1||0||1||50||N
LotSize=0.1||0.1||0.010000||1.000000||N
MagicNumber=129102315||129102315||1||1291023150||N
Slippage=3||3||1||30||N
; === Reversal escape (intrabar, multi-signal) ===
UseReversalEscape=true||false||0||true||N
ReversalEscapeTimeFrame=5||0||0||49153||N
ReversalATRPeriod=14||14||1||140||N
ReversalAdverseAtrMult=5.25||5.25||0.525000||52.500000||N
ReversalSignsRequired=1||2||1||20||N
ReversalRsiVelocity=16.0||16.0||1.600000||160.000000||N
ReversalBodyAtrMult=5.1||5.1||0.510000||51.000000||N
; === Trailing stop ===
UseTrailingStop=true||false||0||true||N
TrailingStopDistancePoints=71.0||100||100||5000||Y
TrailingActivationPoints=41.0||100||100||5000||Y
; === Intrabar give-back (same bar reversals) ===
UseGiveBackExit=true||false||0||true||N
GiveBackATRPeriod=14||14||1||140||N
GiveBackAtrMult=0.1||1.85||0.185000||18.500000||N
GiveBackRequireMfe=true||false||0||true||N
@@ -1,645 +0,0 @@
//+------------------------------------------------------------------+
//| RSIScalping.mq5 |
//| Copyright 2025, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.06"
#include <Trade\Trade.mqh>
#include "../_united/MagicNumberHelpers.mqh"
//--- Input parameters
input ENUM_TIMEFRAMES TimeFrame = PERIOD_H1; // Timeframe for Analysis
input int RSI_Period = 14; // RSI Period
input ENUM_APPLIED_PRICE RSI_Applied_Price = PRICE_CLOSE; // RSI Applied Price
input double RSI_Overbought = 71; // RSI Overbought Level
input double RSI_Oversold = 57; // RSI Oversold Level
input bool UseEntrySlopeFilter = false; // require RSI momentum on entry bars
input double EntryMinSlopePerBar = 1.0; // minimum RSI delta per bar for entry
input double RSI_Target_Buy = 80; // RSI Target for Buy Exit
input double RSI_Target_Sell = 57; // RSI Target for Sell Exit
input int BarsToWait = 1; // Bars to wait when RSI goes against position
input double LotSize = 0.1; // Lot Size
input int MagicNumber = 129102315; // Magic Number
input int Slippage = 3; // Slippage in points
input group "=== Reversal escape (intrabar, multi-signal) ==="
input bool UseReversalEscape = true; // run while in position every tick (now uses ReversalEscapeTimeFrame)
input ENUM_TIMEFRAMES ReversalEscapeTimeFrame = PERIOD_M5; // ATR / RSI velocity / bar signs on this TF (not signal TF)
input int ReversalATRPeriod = 14; // ATR lookback on ReversalEscapeTimeFrame
input double ReversalAdverseAtrMult = 5.25; // close if price vs entry >= this * ATR
input int ReversalSignsRequired = 1; // how many independent signs must align
input double ReversalRsiVelocity = 16.0; // RSI points drop (long) / rise (short) vs prior buffer
input double ReversalBodyAtrMult = 5.1; // last closed bar body >= this * ATR counts as one sign
input group "=== Trailing stop ==="
input bool UseTrailingStop = true; // move SL behind price while in profit
input double TrailingStopDistancePoints = 71.0; // SL distance from current bid/ask (points)
input double TrailingActivationPoints = 41.0; // min profit before trailing (0 = same as distance)
input group "=== Intrabar give-back (same bar reversals) ==="
input bool UseGiveBackExit = true; // exit if price gives back vs best tick since entry
input int GiveBackATRPeriod = 14; // ATR period on signal timeframe (Wilder)
input double GiveBackAtrMult = 0.1; // close when retrace from peak/trough >= this * ATR
input bool GiveBackRequireMfe = true; // long: only after bid was above entry; short: ask below entry
//--- Global variables
CTrade trade;
int rsi_handle;
int rsi_escape_handle = INVALID_HANDLE; // RSI on ReversalEscapeTimeFrame (may alias rsi_handle)
double rsi_buffer[];
double rsi_prev, rsi_current, rsi_two_bars_ago;
bool position_open = false;
int position_ticket = 0;
ENUM_POSITION_TYPE current_position_type = POSITION_TYPE_BUY;
datetime last_bar_time = 0;
bool rsi_against_position = false;
int bars_against_count = 0;
ulong g_giveback_track_ticket = 0;
double g_peak_bid_since_entry = 0.0;
double g_trough_ask_since_entry = 0.0;
void ResetIntrabarGiveBackState();
void TryGiveBackExit();
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Initialize RSI indicator
rsi_handle = iRSI(_Symbol, TimeFrame, RSI_Period, RSI_Applied_Price);
if(rsi_handle == INVALID_HANDLE)
{
return(INIT_FAILED);
}
if(ReversalEscapeTimeFrame == TimeFrame)
rsi_escape_handle = rsi_handle;
else
{
rsi_escape_handle = iRSI(_Symbol, ReversalEscapeTimeFrame, RSI_Period, RSI_Applied_Price);
if(rsi_escape_handle == INVALID_HANDLE)
{
return(INIT_FAILED);
}
}
// Initialize trade object
trade.SetExpertMagicNumber(MagicNumber);
trade.SetDeviationInPoints(Slippage);
trade.SetTypeFilling(ORDER_FILLING_FOK);
// Allocate arrays
ArraySetAsSeries(rsi_buffer, true);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if(rsi_escape_handle != INVALID_HANDLE && rsi_escape_handle != rsi_handle)
IndicatorRelease(rsi_escape_handle);
if(rsi_handle != INVALID_HANDLE)
IndicatorRelease(rsi_handle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
if(Bars(_Symbol, TimeFrame) < RSI_Period + 2)
return;
const datetime current_bar_time = iTime(_Symbol, TimeFrame, 0);
const bool new_bar = (current_bar_time != last_bar_time);
const bool in_pos = position_open || PositionExistsByMagic(_Symbol, (ulong)MagicNumber);
if(!in_pos && !new_bar)
return;
if(!UpdateRSI())
return;
if(in_pos && UseReversalEscape)
TryReversalEscape();
if(in_pos && UseGiveBackExit)
TryGiveBackExit();
if(in_pos && UseTrailingStop)
ApplyTrailingStop();
if(!new_bar)
return;
last_bar_time = current_bar_time;
ResyncPositionFromMarket();
CheckExistingPosition();
if(!position_open && !PositionExistsByMagic(_Symbol, (ulong)MagicNumber))
CheckEntrySignals();
}
//+------------------------------------------------------------------+
//| Update RSI values |
//+------------------------------------------------------------------+
bool UpdateRSI()
{
if(CopyBuffer(rsi_handle, 0, 0, 3, rsi_buffer) < 3)
{
return false;
}
rsi_current = rsi_buffer[0]; // Current bar
rsi_prev = rsi_buffer[1]; // Previous bar
rsi_two_bars_ago = rsi_buffer[2]; // Two bars ago
return true;
}
//+------------------------------------------------------------------+
//| Wilder ATR in price units (signal timeframe) |
//+------------------------------------------------------------------+
double ATRPriceOnTF(const int period)
{
if(period < 1)
return 0.0;
MqlRates rates[];
const int need = period + 2;
if(CopyRates(_Symbol, TimeFrame, 0, need, rates) < need)
return 0.0;
ArraySetAsSeries(rates, true);
double sum = 0.0;
for(int i = 1; i <= period; i++)
{
const double hl = rates[i].high - rates[i].low;
const double hc = MathAbs(rates[i].high - rates[i + 1].close);
const double lc = MathAbs(rates[i].low - rates[i + 1].close);
sum += MathMax(hl, MathMax(hc, lc));
}
return sum / (double)period;
}
//+------------------------------------------------------------------+
//| Wilder ATR on arbitrary timeframe |
//+------------------------------------------------------------------+
double WilderATRForTF(const ENUM_TIMEFRAMES tf, const int period)
{
if(period < 1)
return 0.0;
MqlRates rates[];
const int need = period + 2;
if(CopyRates(_Symbol, tf, 0, need, rates) < need)
return 0.0;
ArraySetAsSeries(rates, true);
double sum = 0.0;
for(int i = 1; i <= period; i++)
{
const double hl = rates[i].high - rates[i].low;
const double hc = MathAbs(rates[i].high - rates[i + 1].close);
const double lc = MathAbs(rates[i].low - rates[i + 1].close);
sum += MathMax(hl, MathMax(hc, lc));
}
return sum / (double)period;
}
//+------------------------------------------------------------------+
//| Independent adverse signs (need ReversalSignsRequired to exit) |
//+------------------------------------------------------------------+
int CountReversalEscapeSigns(const ENUM_POSITION_TYPE ptype, const double atr)
{
if(atr <= 0.0)
return 0;
const double entry = PositionGetDouble(POSITION_PRICE_OPEN);
const double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
const double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
int signs = 0;
double rsi_esc[];
ArraySetAsSeries(rsi_esc, true);
const bool ok_esc_rsi = (rsi_escape_handle != INVALID_HANDLE &&
CopyBuffer(rsi_escape_handle, 0, 0, 2, rsi_esc) >= 2);
if(ptype == POSITION_TYPE_BUY)
{
if(entry - bid >= ReversalAdverseAtrMult * atr)
signs++;
if(ok_esc_rsi && rsi_esc[1] - rsi_esc[0] >= ReversalRsiVelocity)
signs++;
}
else if(ptype == POSITION_TYPE_SELL)
{
if(ask - entry >= ReversalAdverseAtrMult * atr)
signs++;
if(ok_esc_rsi && rsi_esc[0] - rsi_esc[1] >= ReversalRsiVelocity)
signs++;
}
else
return 0;
MqlRates r[];
if(CopyRates(_Symbol, ReversalEscapeTimeFrame, 0, 4, r) >= 4)
{
ArraySetAsSeries(r, true);
const double body = MathAbs(r[1].close - r[1].open);
if(body >= ReversalBodyAtrMult * atr)
{
if(ptype == POSITION_TYPE_BUY && r[1].close < r[1].open)
signs++;
else if(ptype == POSITION_TYPE_SELL && r[1].close > r[1].open)
signs++;
}
if(ptype == POSITION_TYPE_BUY)
{
if(r[1].close < r[2].close && r[2].close < r[3].close)
signs++;
}
else
{
if(r[1].close > r[2].close && r[2].close > r[3].close)
signs++;
}
}
return signs;
}
//+------------------------------------------------------------------+
//| Cut losers fast on violent reversals (evaluated every tick) |
//+------------------------------------------------------------------+
void TryReversalEscape()
{
if(!PositionSelectByMagic(_Symbol, (ulong)MagicNumber))
return;
const ENUM_POSITION_TYPE ptype = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
const double atr = WilderATRForTF(ReversalEscapeTimeFrame, ReversalATRPeriod);
if(atr <= 0.0)
return;
const int n = CountReversalEscapeSigns(ptype, atr);
if(n < ReversalSignsRequired)
return;
ClosePosition();
Print("RSIScalpingXAUUSD: reversal escape TF=", EnumToString(ReversalEscapeTimeFrame),
" signs=", n, " need=", ReversalSignsRequired,
" ATR=", DoubleToString(atr, (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS)));
}
//+------------------------------------------------------------------+
//| Reset give-back peak/trough tracking |
//+------------------------------------------------------------------+
void ResetIntrabarGiveBackState()
{
g_giveback_track_ticket = 0;
g_peak_bid_since_entry = 0.0;
g_trough_ask_since_entry = 0.0;
}
//+------------------------------------------------------------------+
//| Exit when intrabar price gives back sharply vs best since entry |
//+------------------------------------------------------------------+
void TryGiveBackExit()
{
if(!UseGiveBackExit || GiveBackAtrMult <= 0.0)
return;
const ulong ticket = GetPositionTicketByMagic(_Symbol, (ulong)MagicNumber);
if(ticket == 0 || !PositionSelectByTicket(ticket))
{
ResetIntrabarGiveBackState();
return;
}
const ENUM_POSITION_TYPE ptype = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
const double entry = PositionGetDouble(POSITION_PRICE_OPEN);
const double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
const double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
const int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
if(g_giveback_track_ticket != ticket)
{
g_giveback_track_ticket = ticket;
if(ptype == POSITION_TYPE_BUY)
{
g_peak_bid_since_entry = bid;
g_trough_ask_since_entry = 0.0;
}
else
{
g_trough_ask_since_entry = ask;
g_peak_bid_since_entry = 0.0;
}
}
const double atr = ATRPriceOnTF(GiveBackATRPeriod);
if(atr <= 0.0)
return;
const double threshold = GiveBackAtrMult * atr;
if(ptype == POSITION_TYPE_BUY)
{
if(bid > g_peak_bid_since_entry)
g_peak_bid_since_entry = bid;
if(GiveBackRequireMfe && g_peak_bid_since_entry <= entry)
return;
if(g_peak_bid_since_entry - bid >= threshold)
{
ClosePosition();
Print("RSIScalpingXAUUSD: give-back exit BUY retrace=",
DoubleToString(g_peak_bid_since_entry - bid, digits),
" thr=", DoubleToString(threshold, digits));
}
}
else if(ptype == POSITION_TYPE_SELL)
{
if(ask < g_trough_ask_since_entry)
g_trough_ask_since_entry = ask;
if(GiveBackRequireMfe && g_trough_ask_since_entry >= entry)
return;
if(ask - g_trough_ask_since_entry >= threshold)
{
ClosePosition();
Print("RSIScalpingXAUUSD: give-back exit SELL retrace=",
DoubleToString(ask - g_trough_ask_since_entry, digits),
" thr=", DoubleToString(threshold, digits));
}
}
}
//+------------------------------------------------------------------+
//| Trail SL behind favorable price (every tick when enabled) |
//+------------------------------------------------------------------+
void ApplyTrailingStop()
{
if(TrailingStopDistancePoints <= 0.0)
return;
if(!PositionSelectByMagic(_Symbol, (ulong)MagicNumber))
return;
const double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
if(point <= 0.0)
return;
const int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
const double trail_dist = TrailingStopDistancePoints * point;
const double activation_pts = (TrailingActivationPoints > 0.0)
? TrailingActivationPoints
: TrailingStopDistancePoints;
const double activation = activation_pts * point;
const long stops_level = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
const double min_dist = (double)stops_level * point;
const ENUM_POSITION_TYPE ptype = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
const double entry = PositionGetDouble(POSITION_PRICE_OPEN);
const double cur_sl = PositionGetDouble(POSITION_SL);
const double cur_tp = PositionGetDouble(POSITION_TP);
if(ptype == POSITION_TYPE_BUY)
{
const double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
if(bid - entry <= activation)
return;
double new_sl = NormalizeDouble(bid - trail_dist, digits);
if(min_dist > 0.0 && bid - new_sl < min_dist)
new_sl = NormalizeDouble(bid - min_dist, digits);
if(new_sl >= bid || new_sl <= 0.0)
return;
if(cur_sl > 0.0 && new_sl <= cur_sl)
return;
ModifyPositionByMagic(trade, _Symbol, (ulong)MagicNumber, new_sl, cur_tp);
}
else if(ptype == POSITION_TYPE_SELL)
{
const double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
if(entry - ask <= activation)
return;
double new_sl = NormalizeDouble(ask + trail_dist, digits);
if(min_dist > 0.0 && new_sl - ask < min_dist)
new_sl = NormalizeDouble(ask + min_dist, digits);
if(new_sl <= ask || new_sl <= 0.0)
return;
if(cur_sl > 0.0 && new_sl >= cur_sl)
return;
ModifyPositionByMagic(trade, _Symbol, (ulong)MagicNumber, new_sl, cur_tp);
}
}
void ResyncPositionFromMarket()
{
if(position_open)
return;
ulong t = GetPositionTicketByMagic(_Symbol, (ulong)MagicNumber);
if(t == 0 || !PositionSelectByTicket(t))
return;
position_ticket = (int)t;
position_open = true;
current_position_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
}
//+------------------------------------------------------------------+
//| Check existing position for exit conditions |
//+------------------------------------------------------------------+
void CheckExistingPosition()
{
if(!position_open)
{
return;
}
// Check if position still exists with correct magic number
if(!PositionSelectByTicketAndMagic(position_ticket, (ulong)MagicNumber))
{
position_open = false;
position_ticket = 0;
rsi_against_position = false;
bars_against_count = 0;
return;
}
// Exit conditions based on RSI target
if(current_position_type == POSITION_TYPE_BUY)
{
// Check if RSI is against the position (below oversold)
if(rsi_current < RSI_Oversold)
{
if(!rsi_against_position)
{
rsi_against_position = true;
bars_against_count = 1;
}
else
{
bars_against_count++;
}
// Close position if RSI has been against for Y bars
if(bars_against_count >= BarsToWait)
{
ClosePosition();
return;
}
}
else
{
// RSI is no longer against the position, reset counter
if(rsi_against_position)
{
rsi_against_position = false;
bars_against_count = 0;
}
// Exit long position when RSI reaches buy target
if(rsi_current >= RSI_Target_Buy)
{
ClosePosition();
}
}
}
else if(current_position_type == POSITION_TYPE_SELL)
{
// Check if RSI is against the position (above overbought)
if(rsi_current > RSI_Overbought)
{
if(!rsi_against_position)
{
rsi_against_position = true;
bars_against_count = 1;
}
else
{
bars_against_count++;
}
// Close position if RSI has been against for Y bars
if(bars_against_count >= BarsToWait)
{
ClosePosition();
return;
}
}
else
{
// RSI is no longer against the position, reset counter
if(rsi_against_position)
{
rsi_against_position = false;
bars_against_count = 0;
}
// Exit short position when RSI reaches sell target
if(rsi_current <= RSI_Target_Sell)
{
ClosePosition();
}
}
}
}
//+------------------------------------------------------------------+
//| Check for entry signals |
//+------------------------------------------------------------------+
void CheckEntrySignals()
{
const double upSlope1 = rsi_prev - rsi_two_bars_ago; // older->prev
const double upSlope2 = rsi_current - rsi_prev; // prev->current
const double dnSlope1 = rsi_two_bars_ago - rsi_prev; // older->prev
const double dnSlope2 = rsi_prev - rsi_current; // prev->current
const bool buySlopeOk = (!UseEntrySlopeFilter) || (upSlope1 >= EntryMinSlopePerBar && upSlope2 >= EntryMinSlopePerBar);
const bool sellSlopeOk = (!UseEntrySlopeFilter) || (dnSlope1 >= EntryMinSlopePerBar && dnSlope2 >= EntryMinSlopePerBar);
// Buy signal: RSI crosses from oversold to above oversold (checking the actual crossover)
if(rsi_two_bars_ago <= RSI_Oversold && rsi_prev > RSI_Oversold && buySlopeOk)
{
OpenBuyPosition();
}
// Sell signal: RSI crosses from overbought to below overbought (checking the actual crossover)
if(rsi_two_bars_ago >= RSI_Overbought && rsi_prev < RSI_Overbought && sellSlopeOk)
{
OpenSellPosition();
}
}
//+------------------------------------------------------------------+
//| Open buy position |
//+------------------------------------------------------------------+
void OpenBuyPosition()
{
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
if(trade.Buy(LotSize, _Symbol, ask, 0, 0, "RSI Scalping Buy"))
{
const ulong t = GetPositionTicketByMagic(_Symbol, (ulong)MagicNumber);
if(t > 0 && PositionSelectByTicketSymbolAndMagic(t, _Symbol, (ulong)MagicNumber))
{
position_ticket = (int)t;
position_open = true;
current_position_type = POSITION_TYPE_BUY;
}
}
}
//+------------------------------------------------------------------+
//| Open sell position |
//+------------------------------------------------------------------+
void OpenSellPosition()
{
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
if(trade.Sell(LotSize, _Symbol, bid, 0, 0, "RSI Scalping Sell"))
{
const ulong t = GetPositionTicketByMagic(_Symbol, (ulong)MagicNumber);
if(t > 0 && PositionSelectByTicketSymbolAndMagic(t, _Symbol, (ulong)MagicNumber))
{
position_ticket = (int)t;
position_open = true;
current_position_type = POSITION_TYPE_SELL;
}
}
}
//+------------------------------------------------------------------+
//| Close current position |
//+------------------------------------------------------------------+
void ClosePosition()
{
if(ClosePositionByMagic(trade, _Symbol, (ulong)MagicNumber))
{
position_open = false;
position_ticket = 0;
rsi_against_position = false;
bars_against_count = 0;
ResetIntrabarGiveBackState();
return;
}
if(!PositionExistsByMagic(_Symbol, (ulong)MagicNumber))
{
position_open = false;
position_ticket = 0;
rsi_against_position = false;
bars_against_count = 0;
ResetIntrabarGiveBackState();
return;
}
Print("RSIScalpingXAUUSD: close failed (will retry on next bar). retcode=",
trade.ResultRetcode(), " lastError=", GetLastError());
}
@@ -1,508 +0,0 @@
//+------------------------------------------------------------------+
//| RSI_SecretSauce_XAUUSD.mq5 |
//| Copyright 2025, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.01"
#property description "RSI Secret Sauce Strategy: Wait for RSI to leave 70/30 zone, then enter when it comes back in"
#property description "Based on momentum flip concept - not traditional overbought/oversold"
#include <Trade\Trade.mqh>
#include <Trade\PositionInfo.mqh>
//--- Input Parameters
input group "=== Trading Settings ==="
input string InpSymbol = "XAUUSD"; // Default gold; same numbers as secret_sauce.set (that file uses BTCUSD as symbol)
input double InpLotSize = 0.1; // Lot Size (Profiles/Tester/secret_sauce.set)
input int InpMagicNumber = 789012; // Magic Number
input int InpSlippage = 10; // Slippage in points
input ENUM_TIMEFRAMES InpTimeframe = PERIOD_M30; // Trading Timeframe (set value 30 = M30)
input group "=== RSI Settings ==="
input int InpRSIPeriod = 16; // RSI Period
input double InpRSIOverbought = 72.5; // RSI Overbought Level
input double InpRSIOversold = 32.5; // RSI Oversold Level
input int InpRSILookback = 60; // RSI Lookback for Peak/Bottom Detection
input group "=== Entry Logic ==="
input int InpPeakBars = 2; // Bars to confirm peak/bottom
input bool InpRequireDivergence = false; // Require divergence confirmation (optional)
input group "=== Risk Management ==="
input double InpStopLossATR = 2.75; // Stop Loss (ATR multiples)
input double InpTakeProfitATR = 5.0; // Take Profit (ATR multiples)
input int InpATRPeriod = 14; // ATR Period
input bool InpUseSwingStopLoss = false; // Use previous swing high/low for stop loss
input int InpSwingLookback = 30; // Bars to look back for swing points
input group "=== Position Management ==="
input int InpMaxPositions = 1; // Max Simultaneous Positions
input int InpMinBarsBetweenTrades = 7; // Min Bars Between Trades
//--- Global Variables
CTrade trade;
CPositionInfo positionInfo;
string actualSymbol;
int rsiHandle = INVALID_HANDLE;
int atrHandle = INVALID_HANDLE;
double rsiBuffer[];
double atrBuffer[];
double highBuffer[];
double lowBuffer[];
// RSI state tracking
bool rsiWasOverbought = false; // RSI was above 70
bool rsiWasOversold = false; // RSI was below 30
bool rsiBackInRange = false; // RSI came back into range
datetime lastRSIExitTime = 0; // When RSI left the range
datetime lastRSIReentryTime = 0; // When RSI came back in
// Trade tracking
datetime lastTradeTime = 0;
int barsSinceLastTrade = 0;
datetime lastBarTime = 0;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Determine actual symbol
if(InpSymbol == "" || InpSymbol == NULL)
actualSymbol = _Symbol;
else
actualSymbol = InpSymbol;
// Check if symbol exists
if(!SymbolInfoInteger(actualSymbol, SYMBOL_SELECT))
{
Print("Error: Symbol ", actualSymbol, " not found. Using chart symbol.");
actualSymbol = _Symbol;
}
// Initialize RSI indicator
rsiHandle = iRSI(actualSymbol, InpTimeframe, InpRSIPeriod, PRICE_CLOSE);
if(rsiHandle == INVALID_HANDLE)
{
Print("Error creating RSI indicator");
return INIT_FAILED;
}
ArraySetAsSeries(rsiBuffer, true);
// Initialize ATR indicator
atrHandle = iATR(actualSymbol, InpTimeframe, InpATRPeriod);
if(atrHandle == INVALID_HANDLE)
{
Print("Error creating ATR indicator");
return INIT_FAILED;
}
ArraySetAsSeries(atrBuffer, true);
// Initialize price buffers
ArraySetAsSeries(highBuffer, true);
ArraySetAsSeries(lowBuffer, true);
// Set trade parameters
trade.SetExpertMagicNumber(InpMagicNumber);
trade.SetDeviationInPoints(InpSlippage);
trade.SetTypeFilling(ORDER_FILLING_FOK);
Print("=== RSI Secret Sauce Strategy Initialized ===");
Print("Symbol: ", actualSymbol);
Print("Timeframe: ", EnumToString(InpTimeframe));
Print("RSI Period: ", InpRSIPeriod, " | Overbought: ", InpRSIOverbought, " | Oversold: ", InpRSIOversold);
Print("Stop Loss: ", InpStopLossATR, "x ATR | Take Profit: ", InpTakeProfitATR, "x ATR");
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if(rsiHandle != INVALID_HANDLE)
IndicatorRelease(rsiHandle);
if(atrHandle != INVALID_HANDLE)
IndicatorRelease(atrHandle);
Print("Expert Advisor deinitialized. Reason: ", reason);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// Check if we have enough bars
int requiredBars = MathMax(InpRSILookback, InpSwingLookback) + 10;
if(Bars(actualSymbol, InpTimeframe) < requiredBars)
return;
// Check if this is a new bar (wait for candle close)
datetime currentBarTime = iTime(actualSymbol, InpTimeframe, 0);
if(currentBarTime == lastBarTime)
return; // Still the same bar, don't process
lastBarTime = currentBarTime;
// Update indicators
if(!UpdateIndicators())
return;
// Update RSI state tracking
UpdateRSIState();
// Check existing positions
CheckExistingPositions();
// Check for entry signals
if(CanOpenNewPosition())
{
CheckEntrySignals();
}
}
//+------------------------------------------------------------------+
//| Update indicator values |
//+------------------------------------------------------------------+
bool UpdateIndicators()
{
// Update RSI (need enough bars for lookback)
int rsiBarsNeeded = InpRSILookback + 5;
if(CopyBuffer(rsiHandle, 0, 0, rsiBarsNeeded, rsiBuffer) < rsiBarsNeeded)
return false;
// Update ATR
if(CopyBuffer(atrHandle, 0, 0, 2, atrBuffer) < 2)
return false;
// Update price buffers for swing detection
if(CopyHigh(actualSymbol, InpTimeframe, 0, InpSwingLookback + 5, highBuffer) < InpSwingLookback + 5)
return false;
if(CopyLow(actualSymbol, InpTimeframe, 0, InpSwingLookback + 5, lowBuffer) < InpSwingLookback + 5)
return false;
return true;
}
//+------------------------------------------------------------------+
//| Update RSI state tracking |
//+------------------------------------------------------------------+
void UpdateRSIState()
{
double rsiCurrent = rsiBuffer[0];
double rsiPrev = rsiBuffer[1];
// Check if RSI left overbought zone (was above 70, now below 70)
if(rsiPrev >= InpRSIOverbought && rsiCurrent < InpRSIOverbought)
{
rsiWasOverbought = true;
rsiBackInRange = true;
lastRSIExitTime = TimeCurrent();
lastRSIReentryTime = TimeCurrent();
Print(TimeToString(TimeCurrent()), " - RSI left overbought zone (", rsiPrev, " -> ", rsiCurrent, ")");
}
// Check if RSI left oversold zone (was below 30, now above 30)
if(rsiPrev <= InpRSIOversold && rsiCurrent > InpRSIOversold)
{
rsiWasOversold = true;
rsiBackInRange = true;
lastRSIExitTime = TimeCurrent();
lastRSIReentryTime = TimeCurrent();
Print(TimeToString(TimeCurrent()), " - RSI left oversold zone (", rsiPrev, " -> ", rsiCurrent, ")");
}
// Reset flags if RSI goes back to extreme
if(rsiCurrent >= InpRSIOverbought)
{
rsiWasOverbought = false;
rsiBackInRange = false;
}
if(rsiCurrent <= InpRSIOversold)
{
rsiWasOversold = false;
rsiBackInRange = false;
}
}
//+------------------------------------------------------------------+
//| Check if we can open a new position |
//+------------------------------------------------------------------+
bool CanOpenNewPosition()
{
// Check max positions
int positionCount = 0;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(positionInfo.SelectByIndex(i))
{
if(positionInfo.Symbol() == actualSymbol && positionInfo.Magic() == InpMagicNumber)
positionCount++;
}
}
if(positionCount >= InpMaxPositions)
return false;
// Check minimum bars between trades
if(lastTradeTime > 0)
{
int barsSince = Bars(actualSymbol, InpTimeframe, lastTradeTime, TimeCurrent());
if(barsSince < InpMinBarsBetweenTrades)
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| Check for entry signals |
//+------------------------------------------------------------------+
void CheckEntrySignals()
{
// LONG Entry: RSI was overbought (>70), came back in range, now look for peak
if(rsiWasOverbought && rsiBackInRange)
{
// Check if RSI is back in normal range (below 70)
if(rsiBuffer[0] < InpRSIOverbought)
{
// Look for a peak in RSI after re-entry
if(IsRSIPeak())
{
Print(TimeToString(TimeCurrent()), " - LONG Signal: RSI peak detected after leaving overbought zone");
OpenPosition(POSITION_TYPE_BUY);
}
}
}
// SHORT Entry: RSI was oversold (<30), came back in range, now look for bottom
if(rsiWasOversold && rsiBackInRange)
{
// Check if RSI is back in normal range (above 30)
if(rsiBuffer[0] > InpRSIOversold)
{
// Look for a bottom in RSI after re-entry
if(IsRSIBottom())
{
Print(TimeToString(TimeCurrent()), " - SHORT Signal: RSI bottom detected after leaving oversold zone");
OpenPosition(POSITION_TYPE_SELL);
}
}
}
}
//+------------------------------------------------------------------+
//| Check if RSI is forming a peak (for LONG entry) |
//+------------------------------------------------------------------+
bool IsRSIPeak()
{
// We need at least InpPeakBars + 1 bars to confirm a peak
if(ArraySize(rsiBuffer) < InpPeakBars + 2)
return false;
// Check if current RSI is higher than previous bars (forming a peak)
double currentRSI = rsiBuffer[0];
bool isPeak = true;
// Check if current is higher than the next few bars
for(int i = 1; i <= InpPeakBars; i++)
{
if(rsiBuffer[i] >= currentRSI)
{
isPeak = false;
break;
}
}
// Also check if previous bar was lower (confirming upward movement before peak)
if(rsiBuffer[1] >= currentRSI)
isPeak = false;
return isPeak;
}
//+------------------------------------------------------------------+
//| Check if RSI is forming a bottom (for SHORT entry) |
//+------------------------------------------------------------------+
bool IsRSIBottom()
{
// We need at least InpPeakBars + 1 bars to confirm a bottom
if(ArraySize(rsiBuffer) < InpPeakBars + 2)
return false;
// Check if current RSI is lower than previous bars (forming a bottom)
double currentRSI = rsiBuffer[0];
bool isBottom = true;
// Check if current is lower than the next few bars
for(int i = 1; i <= InpPeakBars; i++)
{
if(rsiBuffer[i] <= currentRSI)
{
isBottom = false;
break;
}
}
// Also check if previous bar was higher (confirming downward movement before bottom)
if(rsiBuffer[1] <= currentRSI)
isBottom = false;
return isBottom;
}
//+------------------------------------------------------------------+
//| Open position |
//+------------------------------------------------------------------+
void OpenPosition(ENUM_POSITION_TYPE type)
{
double price = (type == POSITION_TYPE_BUY) ?
SymbolInfoDouble(actualSymbol, SYMBOL_ASK) :
SymbolInfoDouble(actualSymbol, SYMBOL_BID);
if(price <= 0)
return;
// Calculate stop loss and take profit
double sl = 0.0, tp = 0.0;
if(!CalculateStops(price, type, sl, tp))
{
Print("Error: Failed to calculate stops");
return;
}
string comment = "RSI_Secret_" + (type == POSITION_TYPE_BUY ? "LONG" : "SHORT");
bool result = false;
if(type == POSITION_TYPE_BUY)
result = trade.Buy(InpLotSize, actualSymbol, 0, sl, tp, comment);
else
result = trade.Sell(InpLotSize, actualSymbol, 0, sl, tp, comment);
if(result)
{
lastTradeTime = TimeCurrent();
ulong ticket = trade.ResultOrder();
Print(TimeToString(TimeCurrent()), " - Position opened: ", comment, " Ticket: ", ticket,
" Price: ", price, " SL: ", sl, " TP: ", tp);
// Reset RSI state after opening position
if(type == POSITION_TYPE_BUY)
rsiWasOverbought = false;
else
rsiWasOversold = false;
rsiBackInRange = false;
}
else
{
Print("Failed to open position: ", comment, " Error: ",
trade.ResultRetcode(), " - ", trade.ResultRetcodeDescription());
}
}
//+------------------------------------------------------------------+
//| Calculate stop loss and take profit |
//+------------------------------------------------------------------+
bool CalculateStops(double price, ENUM_POSITION_TYPE type, double &sl, double &tp)
{
double atrValue = atrBuffer[0];
if(atrValue <= 0)
atrValue = price * 0.01; // Fallback: 1% of price
double slDistance = atrValue * InpStopLossATR;
double tpDistance = atrValue * InpTakeProfitATR;
int digits = (int)SymbolInfoInteger(actualSymbol, SYMBOL_DIGITS);
double point = SymbolInfoDouble(actualSymbol, SYMBOL_POINT);
int stopsLevel = (int)SymbolInfoInteger(actualSymbol, SYMBOL_TRADE_STOPS_LEVEL);
double minStopDistance = MathMax(stopsLevel * point, point * 10);
// Use swing-based stop loss if enabled
if(InpUseSwingStopLoss)
{
double swingStop = GetSwingStopLoss(price, type);
if(swingStop > 0)
{
if(type == POSITION_TYPE_BUY)
{
if(swingStop < price && (price - swingStop) > minStopDistance)
slDistance = price - swingStop;
}
else
{
if(swingStop > price && (swingStop - price) > minStopDistance)
slDistance = swingStop - price;
}
}
}
// Ensure minimum distance
if(slDistance < minStopDistance)
slDistance = minStopDistance;
if(tpDistance < minStopDistance)
tpDistance = minStopDistance;
if(type == POSITION_TYPE_BUY)
{
sl = NormalizeDouble(price - slDistance, digits);
tp = NormalizeDouble(price + tpDistance, digits);
}
else
{
sl = NormalizeDouble(price + slDistance, digits);
tp = NormalizeDouble(price - tpDistance, digits);
}
return true;
}
//+------------------------------------------------------------------+
//| Get swing-based stop loss (previous swing high/low) |
//+------------------------------------------------------------------+
double GetSwingStopLoss(double currentPrice, ENUM_POSITION_TYPE type)
{
// For LONG: find previous swing low
// For SHORT: find previous swing high
if(type == POSITION_TYPE_BUY)
{
// Find the lowest low in the lookback period
double lowestLow = lowBuffer[0];
for(int i = 1; i < InpSwingLookback && i < ArraySize(lowBuffer); i++)
{
if(lowBuffer[i] < lowestLow)
lowestLow = lowBuffer[i];
}
return lowestLow;
}
else
{
// Find the highest high in the lookback period
double highestHigh = highBuffer[0];
for(int i = 1; i < InpSwingLookback && i < ArraySize(highBuffer); i++)
{
if(highBuffer[i] > highestHigh)
highestHigh = highBuffer[i];
}
return highestHigh;
}
}
//+------------------------------------------------------------------+
//| Check existing positions |
//+------------------------------------------------------------------+
void CheckExistingPositions()
{
// Position management can be added here if needed
// For now, positions are managed by TP/SL
}
//+------------------------------------------------------------------+
@@ -1,284 +0,0 @@
#property strict
#property version "1.00"
#include <Trade/Trade.mqh>
input ENUM_TIMEFRAMES InpHigherTF = PERIOD_H4; // Higher timeframe for MA/cross points
input int InpMAPeriod = 150; // MA period
input ENUM_MA_METHOD InpMAMethod = MODE_SMMA; // MA method
input ENUM_APPLIED_PRICE InpAppliedPrice = PRICE_OPEN; // MA applied price
input int InpHTFBarsToScan = 1200; // HTF bars to scan for crossings
input double InpLineTouchTolerance = 170; // Pullback touch tolerance (points)
input double InpBreakBuffer = 90; // Break confirmation buffer (points)
input double InpLots = 0.10; // Position size
input long InpMagic = 26042501; // Magic number
input bool InpDrawTrendline = true; // Draw detected trendline
CTrade trade;
int g_maHandle = INVALID_HANDLE;
datetime g_lastBarTime = 0;
string g_lineName = "SimpleTrendline_Basis";
struct TrendlineModel
{
datetime t1;
datetime t2;
datetime t3;
double p1;
double p2;
double p3;
double a;
double b;
bool valid;
};
bool IsNewBar()
{
datetime t = iTime(_Symbol, _Period, 0);
if(t == 0)
return false;
if(t != g_lastBarTime)
{
g_lastBarTime = t;
return true;
}
return false;
}
int FindRecentCrossPoints(datetime &times[], double &prices[])
{
ArrayResize(times, 0);
ArrayResize(prices, 0);
if(g_maHandle == INVALID_HANDLE)
return 0;
int needBars = MathMax(InpHTFBarsToScan, InpMAPeriod + 20);
MqlRates rates[];
double maBuf[];
int copiedRates = CopyRates(_Symbol, InpHigherTF, 0, needBars, rates);
int copiedMa = CopyBuffer(g_maHandle, 0, 0, needBars, maBuf);
if(copiedRates <= 5 || copiedMa <= 5)
return 0;
int bars = MathMin(copiedRates, copiedMa);
ArraySetAsSeries(rates, true);
ArraySetAsSeries(maBuf, true);
for(int i = 2; i < bars - 1; i++)
{
double d0 = rates[i].close - maBuf[i];
double d1 = rates[i + 1].close - maBuf[i + 1];
if(d0 == 0.0 || d1 == 0.0 || (d0 * d1 < 0.0))
{
int n = ArraySize(times);
ArrayResize(times, n + 1);
ArrayResize(prices, n + 1);
times[n] = rates[i].time;
prices[n] = rates[i].close;
if(ArraySize(times) >= 3)
break;
}
}
return ArraySize(times);
}
bool BuildTrendlineFrom3Points(TrendlineModel &m)
{
m.valid = false;
datetime ts[];
double ps[];
int n = FindRecentCrossPoints(ts, ps);
if(n < 3)
return false;
// We collected from recent to older in series order.
// Re-map as oldest -> newest to stabilize slope direction.
datetime tOld[3];
double pOld[3];
for(int i = 0; i < 3; i++)
{
tOld[i] = ts[2 - i];
pOld[i] = ps[2 - i];
}
long t0 = (long)tOld[0];
double x1 = 0.0;
double x2 = (double)((long)tOld[1] - t0);
double x3 = (double)((long)tOld[2] - t0);
double y1 = pOld[0];
double y2 = pOld[1];
double y3 = pOld[2];
double sx = x1 + x2 + x3;
double sy = y1 + y2 + y3;
double sxx = x1 * x1 + x2 * x2 + x3 * x3;
double sxy = x1 * y1 + x2 * y2 + x3 * y3;
double den = 3.0 * sxx - sx * sx;
if(MathAbs(den) < 1e-10)
return false;
m.a = (3.0 * sxy - sx * sy) / den;
m.b = (sy - m.a * sx) / 3.0;
m.t1 = tOld[0];
m.t2 = tOld[1];
m.t3 = tOld[2];
m.p1 = pOld[0];
m.p2 = pOld[1];
m.p3 = pOld[2];
m.valid = true;
return true;
}
double TrendlinePriceAtTime(const TrendlineModel &m, datetime t)
{
if(!m.valid)
return 0.0;
double x = (double)((long)t - (long)m.t1);
return m.a * x + m.b;
}
void DrawTrendline(const TrendlineModel &m)
{
if(!InpDrawTrendline || !m.valid)
return;
datetime tStart = m.t1;
datetime tEnd = iTime(_Symbol, _Period, 0);
if(tEnd <= tStart)
tEnd = m.t3 + PeriodSeconds(_Period) * 20;
double pStart = TrendlinePriceAtTime(m, tStart);
double pEnd = TrendlinePriceAtTime(m, tEnd);
if(ObjectFind(0, g_lineName) < 0)
ObjectCreate(0, g_lineName, OBJ_TREND, 0, tStart, pStart, tEnd, pEnd);
else
{
ObjectMove(0, g_lineName, 0, tStart, pStart);
ObjectMove(0, g_lineName, 1, tEnd, pEnd);
}
ObjectSetInteger(0, g_lineName, OBJPROP_RAY_RIGHT, true);
ObjectSetInteger(0, g_lineName, OBJPROP_COLOR, clrGold);
ObjectSetInteger(0, g_lineName, OBJPROP_WIDTH, 2);
}
bool GetCurrentPosition(long &type, double &volume)
{
if(!PositionSelect(_Symbol))
return false;
if((long)PositionGetInteger(POSITION_MAGIC) != InpMagic)
return false;
type = PositionGetInteger(POSITION_TYPE);
volume = PositionGetDouble(POSITION_VOLUME);
return true;
}
void TryExitOnBreak(const TrendlineModel &m)
{
long posType;
double vol;
if(!GetCurrentPosition(posType, vol))
return;
double close1 = iClose(_Symbol, _Period, 1);
datetime t1 = iTime(_Symbol, _Period, 1);
double line1 = TrendlinePriceAtTime(m, t1);
double buf = InpBreakBuffer * _Point;
bool closePos = false;
if(posType == POSITION_TYPE_BUY && close1 < (line1 - buf))
closePos = true;
if(posType == POSITION_TYPE_SELL && close1 > (line1 + buf))
closePos = true;
if(closePos)
trade.PositionClose(_Symbol);
}
void TryPullbackEntry(const TrendlineModel &m)
{
long posType;
double vol;
if(GetCurrentPosition(posType, vol))
return;
MqlRates bars1[], bars2[];
if(CopyRates(_Symbol, _Period, 1, 1, bars1) != 1)
return;
if(CopyRates(_Symbol, _Period, 2, 1, bars2) != 1)
return;
if(ArraySize(bars1) < 1 || ArraySize(bars2) < 1)
return;
MqlRates b1 = bars1[0];
MqlRates b2 = bars2[0];
double line1 = TrendlinePriceAtTime(m, b1.time);
double tol = InpLineTouchTolerance * _Point;
bool upTrend = (m.a > 0.0);
bool downTrend = (m.a < 0.0);
if(upTrend)
{
bool touched = (b1.low <= (line1 + tol));
bool reclaim = (b1.close > line1);
bool bullish = (b1.close > b1.open);
bool stillHealthy = (b2.close >= TrendlinePriceAtTime(m, b2.time) - tol);
if(touched && reclaim && bullish && stillHealthy)
{
trade.Buy(InpLots, _Symbol, 0.0, 0.0, 0.0, "Pullback buy");
}
}
else if(downTrend)
{
bool touched = (b1.high >= (line1 - tol));
bool reject = (b1.close < line1);
bool bearish = (b1.close < b1.open);
bool stillWeak = (b2.close <= TrendlinePriceAtTime(m, b2.time) + tol);
if(touched && reject && bearish && stillWeak)
{
trade.Sell(InpLots, _Symbol, 0.0, 0.0, 0.0, "Pullback sell");
}
}
}
int OnInit()
{
g_maHandle = iMA(_Symbol, InpHigherTF, InpMAPeriod, 0, InpMAMethod, InpAppliedPrice);
if(g_maHandle == INVALID_HANDLE)
return INIT_FAILED;
trade.SetExpertMagicNumber(InpMagic);
g_lastBarTime = 0;
return INIT_SUCCEEDED;
}
void OnDeinit(const int reason)
{
if(g_maHandle != INVALID_HANDLE)
IndicatorRelease(g_maHandle);
if(ObjectFind(0, g_lineName) >= 0)
ObjectDelete(0, g_lineName);
}
void OnTick()
{
if(!IsNewBar())
return;
TrendlineModel m;
if(!BuildTrendlineFrom3Points(m))
return;
DrawTrendline(m);
TryExitOnBreak(m);
TryPullbackEntry(m);
}
@@ -1,14 +0,0 @@
; SimpleTrendline.mq5 optimization preset
; Strategy Tester -> Inputs -> Load
; Focus: trendline pullback entries + break exits (no broker SL/TP)
;
InpHigherTF=16385||16385||0||16388||Y
InpMAPeriod=50||20||5||200||Y
InpMAMethod=1||0||1||3||Y
InpAppliedPrice=0||0||1||6||Y
InpHTFBarsToScan=400||200||100||1200||Y
InpLineTouchTolerance=100.0||30.0||10.0||300.0||Y
InpBreakBuffer=30.0||5.0||5.0||120.0||Y
InpLots=0.10||0.10||0.01||0.10||N
InpMagic=26042501||26042501||1||26042501||N
InpDrawTrendline=false||false||0||true||N
@@ -1,284 +0,0 @@
#property strict
#property version "1.00"
#include <Trade/Trade.mqh>
input ENUM_TIMEFRAMES InpHigherTF = PERIOD_M15; // Higher timeframe for MA/cross points
input int InpMAPeriod = 65; // MA period
input ENUM_MA_METHOD InpMAMethod = MODE_LWMA; // MA method
input ENUM_APPLIED_PRICE InpAppliedPrice = PRICE_OPEN; // MA applied price
input int InpHTFBarsToScan = 1200; // HTF bars to scan for crossings
input double InpLineTouchTolerance = 100; // Pullback touch tolerance (points)
input double InpBreakBuffer = 80; // Break confirmation buffer (points)
input double InpLots = 0.10; // Position size
input long InpMagic = 26042501; // Magic number
input bool InpDrawTrendline = true; // Draw detected trendline
CTrade trade;
int g_maHandle = INVALID_HANDLE;
datetime g_lastBarTime = 0;
string g_lineName = "SimpleTrendline_Basis";
struct TrendlineModel
{
datetime t1;
datetime t2;
datetime t3;
double p1;
double p2;
double p3;
double a;
double b;
bool valid;
};
bool IsNewBar()
{
datetime t = iTime(_Symbol, _Period, 0);
if(t == 0)
return false;
if(t != g_lastBarTime)
{
g_lastBarTime = t;
return true;
}
return false;
}
int FindRecentCrossPoints(datetime &times[], double &prices[])
{
ArrayResize(times, 0);
ArrayResize(prices, 0);
if(g_maHandle == INVALID_HANDLE)
return 0;
int needBars = MathMax(InpHTFBarsToScan, InpMAPeriod + 20);
MqlRates rates[];
double maBuf[];
int copiedRates = CopyRates(_Symbol, InpHigherTF, 0, needBars, rates);
int copiedMa = CopyBuffer(g_maHandle, 0, 0, needBars, maBuf);
if(copiedRates <= 5 || copiedMa <= 5)
return 0;
int bars = MathMin(copiedRates, copiedMa);
ArraySetAsSeries(rates, true);
ArraySetAsSeries(maBuf, true);
for(int i = 2; i < bars - 1; i++)
{
double d0 = rates[i].close - maBuf[i];
double d1 = rates[i + 1].close - maBuf[i + 1];
if(d0 == 0.0 || d1 == 0.0 || (d0 * d1 < 0.0))
{
int n = ArraySize(times);
ArrayResize(times, n + 1);
ArrayResize(prices, n + 1);
times[n] = rates[i].time;
prices[n] = rates[i].close;
if(ArraySize(times) >= 3)
break;
}
}
return ArraySize(times);
}
bool BuildTrendlineFrom3Points(TrendlineModel &m)
{
m.valid = false;
datetime ts[];
double ps[];
int n = FindRecentCrossPoints(ts, ps);
if(n < 3)
return false;
// We collected from recent to older in series order.
// Re-map as oldest -> newest to stabilize slope direction.
datetime tOld[3];
double pOld[3];
for(int i = 0; i < 3; i++)
{
tOld[i] = ts[2 - i];
pOld[i] = ps[2 - i];
}
long t0 = (long)tOld[0];
double x1 = 0.0;
double x2 = (double)((long)tOld[1] - t0);
double x3 = (double)((long)tOld[2] - t0);
double y1 = pOld[0];
double y2 = pOld[1];
double y3 = pOld[2];
double sx = x1 + x2 + x3;
double sy = y1 + y2 + y3;
double sxx = x1 * x1 + x2 * x2 + x3 * x3;
double sxy = x1 * y1 + x2 * y2 + x3 * y3;
double den = 3.0 * sxx - sx * sx;
if(MathAbs(den) < 1e-10)
return false;
m.a = (3.0 * sxy - sx * sy) / den;
m.b = (sy - m.a * sx) / 3.0;
m.t1 = tOld[0];
m.t2 = tOld[1];
m.t3 = tOld[2];
m.p1 = pOld[0];
m.p2 = pOld[1];
m.p3 = pOld[2];
m.valid = true;
return true;
}
double TrendlinePriceAtTime(const TrendlineModel &m, datetime t)
{
if(!m.valid)
return 0.0;
double x = (double)((long)t - (long)m.t1);
return m.a * x + m.b;
}
void DrawTrendline(const TrendlineModel &m)
{
if(!InpDrawTrendline || !m.valid)
return;
datetime tStart = m.t1;
datetime tEnd = iTime(_Symbol, _Period, 0);
if(tEnd <= tStart)
tEnd = m.t3 + PeriodSeconds(_Period) * 20;
double pStart = TrendlinePriceAtTime(m, tStart);
double pEnd = TrendlinePriceAtTime(m, tEnd);
if(ObjectFind(0, g_lineName) < 0)
ObjectCreate(0, g_lineName, OBJ_TREND, 0, tStart, pStart, tEnd, pEnd);
else
{
ObjectMove(0, g_lineName, 0, tStart, pStart);
ObjectMove(0, g_lineName, 1, tEnd, pEnd);
}
ObjectSetInteger(0, g_lineName, OBJPROP_RAY_RIGHT, true);
ObjectSetInteger(0, g_lineName, OBJPROP_COLOR, clrGold);
ObjectSetInteger(0, g_lineName, OBJPROP_WIDTH, 2);
}
bool GetCurrentPosition(long &type, double &volume)
{
if(!PositionSelect(_Symbol))
return false;
if((long)PositionGetInteger(POSITION_MAGIC) != InpMagic)
return false;
type = PositionGetInteger(POSITION_TYPE);
volume = PositionGetDouble(POSITION_VOLUME);
return true;
}
void TryExitOnBreak(const TrendlineModel &m)
{
long posType;
double vol;
if(!GetCurrentPosition(posType, vol))
return;
double close1 = iClose(_Symbol, _Period, 1);
datetime t1 = iTime(_Symbol, _Period, 1);
double line1 = TrendlinePriceAtTime(m, t1);
double buf = InpBreakBuffer * _Point;
bool closePos = false;
if(posType == POSITION_TYPE_BUY && close1 < (line1 - buf))
closePos = true;
if(posType == POSITION_TYPE_SELL && close1 > (line1 + buf))
closePos = true;
if(closePos)
trade.PositionClose(_Symbol);
}
void TryPullbackEntry(const TrendlineModel &m)
{
long posType;
double vol;
if(GetCurrentPosition(posType, vol))
return;
MqlRates bars1[], bars2[];
if(CopyRates(_Symbol, _Period, 1, 1, bars1) != 1)
return;
if(CopyRates(_Symbol, _Period, 2, 1, bars2) != 1)
return;
if(ArraySize(bars1) < 1 || ArraySize(bars2) < 1)
return;
MqlRates b1 = bars1[0];
MqlRates b2 = bars2[0];
double line1 = TrendlinePriceAtTime(m, b1.time);
double tol = InpLineTouchTolerance * _Point;
bool upTrend = (m.a > 0.0);
bool downTrend = (m.a < 0.0);
if(upTrend)
{
bool touched = (b1.low <= (line1 + tol));
bool reclaim = (b1.close > line1);
bool bullish = (b1.close > b1.open);
bool stillHealthy = (b2.close >= TrendlinePriceAtTime(m, b2.time) - tol);
if(touched && reclaim && bullish && stillHealthy)
{
trade.Buy(InpLots, _Symbol, 0.0, 0.0, 0.0, "Pullback buy");
}
}
else if(downTrend)
{
bool touched = (b1.high >= (line1 - tol));
bool reject = (b1.close < line1);
bool bearish = (b1.close < b1.open);
bool stillWeak = (b2.close <= TrendlinePriceAtTime(m, b2.time) + tol);
if(touched && reject && bearish && stillWeak)
{
trade.Sell(InpLots, _Symbol, 0.0, 0.0, 0.0, "Pullback sell");
}
}
}
int OnInit()
{
g_maHandle = iMA(_Symbol, InpHigherTF, InpMAPeriod, 0, InpMAMethod, InpAppliedPrice);
if(g_maHandle == INVALID_HANDLE)
return INIT_FAILED;
trade.SetExpertMagicNumber(InpMagic);
g_lastBarTime = 0;
return INIT_SUCCEEDED;
}
void OnDeinit(const int reason)
{
if(g_maHandle != INVALID_HANDLE)
IndicatorRelease(g_maHandle);
if(ObjectFind(0, g_lineName) >= 0)
ObjectDelete(0, g_lineName);
}
void OnTick()
{
if(!IsNewBar())
return;
TrendlineModel m;
if(!BuildTrendlineFrom3Points(m))
return;
DrawTrendline(m);
TryExitOnBreak(m);
TryPullbackEntry(m);
}
@@ -1,14 +0,0 @@
; SimpleTrendline.mq5 optimization preset
; Strategy Tester -> Inputs -> Load
; Focus: trendline pullback entries + break exits (no broker SL/TP)
;
InpHigherTF=16385||16385||0||16388||Y
InpMAPeriod=50||20||5||200||Y
InpMAMethod=1||0||1||3||Y
InpAppliedPrice=0||0||1||6||Y
InpHTFBarsToScan=400||200||100||1200||Y
InpLineTouchTolerance=100.0||30.0||10.0||300.0||Y
InpBreakBuffer=30.0||5.0||5.0||120.0||Y
InpLots=0.10||0.10||0.01||0.10||N
InpMagic=26042501||26042501||1||26042501||N
InpDrawTrendline=false||false||0||true||N
@@ -1,376 +0,0 @@
#property strict
#property version "1.00"
#include <Trade/Trade.mqh>
input ENUM_TIMEFRAMES InpHigherTF = PERIOD_M10; // Higher timeframe for MA/cross points
input int InpMAPeriod = 65; // MA period
input ENUM_MA_METHOD InpMAMethod = MODE_EMA; // MA method
input ENUM_APPLIED_PRICE InpAppliedPrice = PRICE_OPEN; // MA applied price
input int InpHTFBarsToScan = 500; // HTF bars to scan for crossings
input double InpLineTouchTolerance = 220; // Pullback touch tolerance (points)
input double InpBreakBuffer = 110; // Break confirmation buffer (points)
input double InpLots = 0.10; // Position size
input long InpMagic = 26042501; // Magic number
input bool InpDrawTrendline = true; // Draw detected trendline
input bool InpUseSessionModeGate = true; // Block entries when symbol/session disallow opens
input bool InpBypassGateInTester = true; // Ignore gate in Strategy Tester for optimization
CTrade trade;
int g_maHandle = INVALID_HANDLE;
datetime g_lastBarTime = 0;
string g_lineName = "SimpleTrendline_Basis";
datetime g_lastEntryBlockLog = 0;
struct TrendlineModel
{
datetime t1;
datetime t2;
datetime t3;
double p1;
double p2;
double p3;
double a;
double b;
bool valid;
};
bool IsNewBar()
{
datetime t = iTime(_Symbol, _Period, 0);
if(t == 0)
return false;
if(t != g_lastBarTime)
{
g_lastBarTime = t;
return true;
}
return false;
}
int FindRecentCrossPoints(datetime &times[], double &prices[])
{
ArrayResize(times, 0);
ArrayResize(prices, 0);
if(g_maHandle == INVALID_HANDLE)
return 0;
int needBars = MathMax(InpHTFBarsToScan, InpMAPeriod + 20);
MqlRates rates[];
double maBuf[];
int copiedRates = CopyRates(_Symbol, InpHigherTF, 0, needBars, rates);
int copiedMa = CopyBuffer(g_maHandle, 0, 0, needBars, maBuf);
if(copiedRates <= 5 || copiedMa <= 5)
return 0;
int bars = MathMin(copiedRates, copiedMa);
ArraySetAsSeries(rates, true);
ArraySetAsSeries(maBuf, true);
for(int i = 2; i < bars - 1; i++)
{
double d0 = rates[i].close - maBuf[i];
double d1 = rates[i + 1].close - maBuf[i + 1];
if(d0 == 0.0 || d1 == 0.0 || (d0 * d1 < 0.0))
{
int n = ArraySize(times);
ArrayResize(times, n + 1);
ArrayResize(prices, n + 1);
times[n] = rates[i].time;
prices[n] = rates[i].close;
if(ArraySize(times) >= 3)
break;
}
}
return ArraySize(times);
}
bool BuildTrendlineFrom3Points(TrendlineModel &m)
{
m.valid = false;
datetime ts[];
double ps[];
int n = FindRecentCrossPoints(ts, ps);
if(n < 3)
return false;
// We collected from recent to older in series order.
// Re-map as oldest -> newest to stabilize slope direction.
datetime tOld[3];
double pOld[3];
for(int i = 0; i < 3; i++)
{
tOld[i] = ts[2 - i];
pOld[i] = ps[2 - i];
}
long t0 = (long)tOld[0];
double x1 = 0.0;
double x2 = (double)((long)tOld[1] - t0);
double x3 = (double)((long)tOld[2] - t0);
double y1 = pOld[0];
double y2 = pOld[1];
double y3 = pOld[2];
double sx = x1 + x2 + x3;
double sy = y1 + y2 + y3;
double sxx = x1 * x1 + x2 * x2 + x3 * x3;
double sxy = x1 * y1 + x2 * y2 + x3 * y3;
double den = 3.0 * sxx - sx * sx;
if(MathAbs(den) < 1e-10)
return false;
m.a = (3.0 * sxy - sx * sy) / den;
m.b = (sy - m.a * sx) / 3.0;
m.t1 = tOld[0];
m.t2 = tOld[1];
m.t3 = tOld[2];
m.p1 = pOld[0];
m.p2 = pOld[1];
m.p3 = pOld[2];
m.valid = true;
return true;
}
double TrendlinePriceAtTime(const TrendlineModel &m, datetime t)
{
if(!m.valid)
return 0.0;
double x = (double)((long)t - (long)m.t1);
return m.a * x + m.b;
}
void DrawTrendline(const TrendlineModel &m)
{
if(!InpDrawTrendline || !m.valid)
return;
datetime tStart = m.t1;
datetime tEnd = iTime(_Symbol, _Period, 0);
if(tEnd <= tStart)
tEnd = m.t3 + PeriodSeconds(_Period) * 20;
double pStart = TrendlinePriceAtTime(m, tStart);
double pEnd = TrendlinePriceAtTime(m, tEnd);
if(ObjectFind(0, g_lineName) < 0)
ObjectCreate(0, g_lineName, OBJ_TREND, 0, tStart, pStart, tEnd, pEnd);
else
{
ObjectMove(0, g_lineName, 0, tStart, pStart);
ObjectMove(0, g_lineName, 1, tEnd, pEnd);
}
ObjectSetInteger(0, g_lineName, OBJPROP_RAY_RIGHT, true);
ObjectSetInteger(0, g_lineName, OBJPROP_COLOR, clrGold);
ObjectSetInteger(0, g_lineName, OBJPROP_WIDTH, 2);
}
bool GetCurrentPosition(long &type, double &volume)
{
if(!PositionSelect(_Symbol))
return false;
if((long)PositionGetInteger(POSITION_MAGIC) != InpMagic)
return false;
type = PositionGetInteger(POSITION_TYPE);
volume = PositionGetDouble(POSITION_VOLUME);
return true;
}
bool IsWithinAnyTradeSession(const datetime nowServer)
{
MqlDateTime dt;
TimeToStruct(nowServer, dt);
ENUM_DAY_OF_WEEK day = (ENUM_DAY_OF_WEEK)dt.day_of_week;
int nowSec = dt.hour * 3600 + dt.min * 60 + dt.sec;
datetime from = 0;
datetime to = 0;
bool hasAny = false;
for(uint idx = 0; idx < 16; idx++)
{
if(!SymbolInfoSessionTrade(_Symbol, day, idx, from, to))
break;
hasAny = true;
// SymbolInfoSessionTrade returns session boundaries as time-of-day values.
MqlDateTime fdt, tdt;
TimeToStruct(from, fdt);
TimeToStruct(to, tdt);
int fromSec = fdt.hour * 3600 + fdt.min * 60 + fdt.sec;
int toSec = tdt.hour * 3600 + tdt.min * 60 + tdt.sec;
// from==to on some brokers means full-day session.
if(fromSec == toSec)
{
return true;
}
else if(fromSec < toSec)
{
if(nowSec >= fromSec && nowSec <= toSec)
return true;
}
else
{
// Session passes midnight.
if(nowSec >= fromSec || nowSec <= toSec)
return true;
}
}
// If broker does not expose sessions for this symbol, do not block by session.
if(!hasAny)
return true;
return false;
}
bool CanOpenNewPositionNow(const ENUM_ORDER_TYPE orderType)
{
if(!InpUseSessionModeGate)
return true;
if(InpBypassGateInTester && (bool)MQLInfoInteger(MQL_TESTER))
return true;
long tradeMode = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_MODE);
if(tradeMode == SYMBOL_TRADE_MODE_DISABLED ||
tradeMode == SYMBOL_TRADE_MODE_CLOSEONLY)
return false;
if(orderType == ORDER_TYPE_BUY &&
tradeMode == SYMBOL_TRADE_MODE_SHORTONLY)
return false;
if(orderType == ORDER_TYPE_SELL &&
tradeMode == SYMBOL_TRADE_MODE_LONGONLY)
return false;
if(!IsWithinAnyTradeSession(TimeCurrent()))
return false;
return true;
}
void TryExitOnBreak(const TrendlineModel &m)
{
long posType;
double vol;
if(!GetCurrentPosition(posType, vol))
return;
double close1 = iClose(_Symbol, _Period, 1);
datetime t1 = iTime(_Symbol, _Period, 1);
double line1 = TrendlinePriceAtTime(m, t1);
double buf = InpBreakBuffer * _Point;
bool closePos = false;
if(posType == POSITION_TYPE_BUY && close1 < (line1 - buf))
closePos = true;
if(posType == POSITION_TYPE_SELL && close1 > (line1 + buf))
closePos = true;
if(closePos)
trade.PositionClose(_Symbol);
}
void TryPullbackEntry(const TrendlineModel &m)
{
long posType;
double vol;
if(GetCurrentPosition(posType, vol))
return;
MqlRates bars1[], bars2[];
if(CopyRates(_Symbol, _Period, 1, 1, bars1) != 1)
return;
if(CopyRates(_Symbol, _Period, 2, 1, bars2) != 1)
return;
if(ArraySize(bars1) < 1 || ArraySize(bars2) < 1)
return;
MqlRates b1 = bars1[0];
MqlRates b2 = bars2[0];
double line1 = TrendlinePriceAtTime(m, b1.time);
double tol = InpLineTouchTolerance * _Point;
bool upTrend = (m.a > 0.0);
bool downTrend = (m.a < 0.0);
if(upTrend)
{
bool touched = (b1.low <= (line1 + tol));
bool reclaim = (b1.close > line1);
bool bullish = (b1.close > b1.open);
bool stillHealthy = (b2.close >= TrendlinePriceAtTime(m, b2.time) - tol);
if(touched && reclaim && bullish && stillHealthy)
{
if(!CanOpenNewPositionNow(ORDER_TYPE_BUY))
{
datetime nowBar = iTime(_Symbol, _Period, 0);
if(nowBar != g_lastEntryBlockLog)
{
g_lastEntryBlockLog = nowBar;
Print("Buy entry skipped: symbol mode/session does not allow opening now");
}
return;
}
trade.Buy(InpLots, _Symbol, 0.0, 0.0, 0.0, "Pullback buy");
}
}
else if(downTrend)
{
bool touched = (b1.high >= (line1 - tol));
bool reject = (b1.close < line1);
bool bearish = (b1.close < b1.open);
bool stillWeak = (b2.close <= TrendlinePriceAtTime(m, b2.time) + tol);
if(touched && reject && bearish && stillWeak)
{
if(!CanOpenNewPositionNow(ORDER_TYPE_SELL))
{
datetime nowBar = iTime(_Symbol, _Period, 0);
if(nowBar != g_lastEntryBlockLog)
{
g_lastEntryBlockLog = nowBar;
Print("Sell entry skipped: symbol mode/session does not allow opening now");
}
return;
}
trade.Sell(InpLots, _Symbol, 0.0, 0.0, 0.0, "Pullback sell");
}
}
}
int OnInit()
{
g_maHandle = iMA(_Symbol, InpHigherTF, InpMAPeriod, 0, InpMAMethod, InpAppliedPrice);
if(g_maHandle == INVALID_HANDLE)
return INIT_FAILED;
trade.SetExpertMagicNumber(InpMagic);
g_lastBarTime = 0;
return INIT_SUCCEEDED;
}
void OnDeinit(const int reason)
{
if(g_maHandle != INVALID_HANDLE)
IndicatorRelease(g_maHandle);
if(ObjectFind(0, g_lineName) >= 0)
ObjectDelete(0, g_lineName);
}
void OnTick()
{
if(!IsNewBar())
return;
TrendlineModel m;
if(!BuildTrendlineFrom3Points(m))
return;
DrawTrendline(m);
TryExitOnBreak(m);
TryPullbackEntry(m);
}
@@ -1,14 +0,0 @@
; SimpleTrendline.mq5 optimization preset
; Strategy Tester -> Inputs -> Load
; Focus: trendline pullback entries + break exits (no broker SL/TP)
;
InpHigherTF=16385||16385||0||16388||Y
InpMAPeriod=50||20||5||200||Y
InpMAMethod=1||0||1||3||Y
InpAppliedPrice=0||0||1||6||Y
InpHTFBarsToScan=400||200||100||1200||Y
InpLineTouchTolerance=100.0||30.0||10.0||300.0||Y
InpBreakBuffer=30.0||5.0||5.0||120.0||Y
InpLots=0.10||0.10||0.01||0.10||N
InpMagic=26042501||26042501||1||26042501||N
InpDrawTrendline=false||false||0||true||N
@@ -1,173 +0,0 @@
//+------------------------------------------------------------------+
//| 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)
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket == 0)
continue;
if(!PositionSelectByTicket(ticket))
continue;
if(PositionGetString(POSITION_SYMBOL) == symbol &&
(ulong)PositionGetInteger(POSITION_MAGIC) == magic_number)
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| 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)
continue;
if(!PositionSelectByTicket(ticket))
continue;
if(PositionGetString(POSITION_SYMBOL) == symbol &&
(ulong)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)
continue;
if(!PositionSelectByTicket(ticket))
continue;
if(PositionGetString(POSITION_SYMBOL) == symbol &&
(ulong)PositionGetInteger(POSITION_MAGIC) == magic_number)
count++;
}
return count;
}
//+------------------------------------------------------------------+
//| Align volume to SYMBOL_VOLUME_STEP / min / max (avoids Invalid volume) |
//+------------------------------------------------------------------+
double United_NormalizeVolume(const string symbol, double volume)
{
double minLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
double maxLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
double lotStep = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
if(lotStep <= 0.0)
lotStep = 0.01;
double v = MathFloor(volume / lotStep) * lotStep;
if(v < minLot)
v = minLot;
if(v > maxLot)
v = maxLot;
int digits = (int)MathCeil(-MathLog10(lotStep));
if(digits < 0)
digits = 0;
if(digits > 8)
digits = 8;
return NormalizeDouble(v, digits);
}
//+------------------------------------------------------------------+
@@ -1,76 +0,0 @@
# United EA Strategy Configuration Summary
## Strategy Symbols and Magic Numbers
### Strategy 1: DarvasBox
- **Symbol**: XAUUSD (Gold/USD)
- **Magic Number**: 135790
### Strategy 2: EMASlopeDistance
- **Symbol**: XAUUSD (Gold/USD)
- **Magic Number**: 12350
### Strategy 3: RSICrossOverReversal
- **Symbol**: XAUUSD (Gold/USD)
- **Magic Number**: 7
### Strategy 4: RSIMidPointHijack
- **Symbol**: XAUUSD (Gold/USD)
- **Magic Numbers**:
- RSIFollow: 1001
- RSIReverse: 1002
- EMACross: 1003
### Strategy 5: RSI Scalping APPL (Apple)
- **Symbol**: AAPL (Apple stock)
- **Magic Number**: 20001
- **Note**: Changed from "APPL" to "AAPL" (correct ticker symbol)
### Strategy 6: RSI Scalping BTCUSD
- **Symbol**: BTCUSD (Bitcoin/USD)
- **Magic Number**: 123459123
### Strategy 7: RSI Scalping MSFT
- **Symbol**: MSFT (Microsoft stock)
- **Magic Number**: 20002
### Strategy 8: RSI Scalping NVDA
- **Symbol**: NVDA (NVIDIA stock)
- **Magic Number**: 20003
### Strategy 9: RSI Scalping TSLA
- **Symbol**: TSLA (Tesla stock)
- **Magic Number**: 125421321
### Strategy 10: RSI Scalping XAUUSD
- **Symbol**: XAUUSD (Gold/USD)
- **Magic Number**: 129102315
## Important Notes
1. **Stock Symbols**: Stock symbols (AAPL, MSFT, NVDA, TSLA) must be:
- Added to Market Watch in MetaTrader 5
- Available from your broker
- Use the correct ticker symbol (e.g., "AAPL" not "APPL")
2. **Magic Numbers**: All strategies have unique magic numbers to prevent interference:
- Each strategy can be identified by its magic number
- RSIMidPointHijack uses 3 magic numbers (one for each sub-strategy)
3. **Symbol Configuration**: Each strategy trades on its own symbol:
- You can change symbols in the input parameters
- The EA will log warnings if a symbol is not available
- Strategies with unavailable symbols will be skipped (EA continues running)
4. **RSI Scalping Strategies**:
- Each RSI Scalping variant trades on a different symbol
- They all use the same strategy logic but with different parameters
- Buy and sell signals are generated based on RSI levels for each symbol
## Troubleshooting
If stock symbols are not working:
1. Check if the symbol exists in your broker's symbol list
2. Add the symbol to Market Watch in MetaTrader 5
3. Verify the symbol name matches your broker's naming convention
4. Some brokers use prefixes/suffixes (e.g., "NASDAQ:AAPL" or "AAPL.US")
@@ -1,328 +0,0 @@
//+------------------------------------------------------------------+
//| DarvasBoxStrategy.mqh |
//+------------------------------------------------------------------+
// MQL5: no #if — use #ifdef only (no defined() / || in one #if)
#ifdef UNITED_V2_DYNAMIC_LOTS
extern double g_DB_LotSize;
#define DARVAS_TRADE_LOT (g_DB_LotSize)
#else
#ifdef CLUSTER0_ORCHESTRATOR
extern double g_DB_LotSize;
#define DARVAS_TRADE_LOT (g_DB_LotSize)
#else
#define DARVAS_TRADE_LOT 0.01
#endif
#endif
bool InitDarvasBox(string symbol)
{
dbData.symbol = symbol;
dbData.boxHigh = 0;
dbData.boxLow = 0;
dbData.boxFormed = false;
dbData.lastBoxTime = 0;
dbData.boxName = "DarvasBox_" + IntegerToString(DB_MagicNumber) + "_";
// Check if symbol exists
if(!SymbolSelect(symbol, true))
{
Print("DarvasBox: Symbol '", symbol, "' not available in Market Watch. Please add it to Market Watch or check symbol name.");
return false;
}
Sleep(100); // Wait for symbol to be ready
dbData.point = SymbolInfoDouble(symbol, SYMBOL_POINT);
dbData.minStopLevel = SymbolInfoInteger(symbol, SYMBOL_TRADE_STOPS_LEVEL) * dbData.point;
dbData.maHandle = iMA(symbol, DB_TrendTimeframe, DB_MA_Period, 0, DB_MA_Method, DB_MA_Price);
// Same TF as box highs/lows (H1 loop in CalculateDarvasBox). PERIOD_CURRENT breaks when United EA
// runs on a chart timeframe other than H1 (volume/breakout no longer match the box).
dbData.volumeHandle = iVolumes(symbol, PERIOD_H1, VOLUME_TICK);
if(dbData.maHandle == INVALID_HANDLE || dbData.volumeHandle == INVALID_HANDLE)
{
Print("DarvasBox: Error creating indicators for '", symbol, "'");
return false;
}
dbData.trade.SetDeviationInPoints(10);
dbData.trade.SetTypeFilling(ORDER_FILLING_IOC);
dbData.trade.SetAsyncMode(false);
dbData.trade.SetExpertMagicNumber(DB_MagicNumber);
ObjectsDeleteAll(0, dbData.boxName);
dbData.isInitialized = true;
Print("DarvasBox: Successfully initialized for symbol '", symbol, "'");
return true;
}
void DeinitDarvasBox()
{
if(dbData.maHandle != INVALID_HANDLE) IndicatorRelease(dbData.maHandle);
if(dbData.volumeHandle != INVALID_HANDLE) IndicatorRelease(dbData.volumeHandle);
ObjectsDeleteAll(0, dbData.boxName);
}
void DrawDarvasBox()
{
if(!dbData.boxFormed) return;
datetime time1 = iTime(dbData.symbol, PERIOD_H1, DB_BoxPeriod);
datetime time2 = iTime(dbData.symbol, PERIOD_H1, 0);
ObjectsDeleteAll(0, dbData.boxName);
ObjectCreate(0, dbData.boxName + "Top", OBJ_TREND, 0, time1, dbData.boxHigh, time2, dbData.boxHigh);
ObjectCreate(0, dbData.boxName + "Bottom", OBJ_TREND, 0, time1, dbData.boxLow, time2, dbData.boxLow);
ObjectSetInteger(0, dbData.boxName + "Top", OBJPROP_COLOR, DB_BoxColor);
ObjectSetInteger(0, dbData.boxName + "Bottom", OBJPROP_COLOR, DB_BoxColor);
ObjectSetInteger(0, dbData.boxName + "Top", OBJPROP_WIDTH, DB_BoxWidth);
ObjectSetInteger(0, dbData.boxName + "Bottom", OBJPROP_WIDTH, DB_BoxWidth);
ObjectSetInteger(0, dbData.boxName + "Top", OBJPROP_RAY_RIGHT, true);
ObjectSetInteger(0, dbData.boxName + "Bottom", OBJPROP_RAY_RIGHT, true);
}
void CalculateDarvasBox()
{
double high = 0;
double low = DBL_MAX;
// Find highest high and lowest low in the period - EXACTLY like original
for(int i = 0; i < DB_BoxPeriod; i++)
{
high = MathMax(high, iHigh(dbData.symbol, PERIOD_H1, i));
low = MathMin(low, iLow(dbData.symbol, PERIOD_H1, i));
}
double range = high - low;
double allowedRange = DB_BoxDeviation * dbData.point; // Use dbData.point instead of _Point
if(DB_EnableLogging)
{
Print("DarvasBox: Box Calculation - High: ", high, " Low: ", low, " Range: ", range, " Allowed Range: ", allowedRange);
}
// Check if box is formed - EXACTLY like original
if(range <= allowedRange)
{
dbData.boxHigh = high;
dbData.boxLow = low;
dbData.boxFormed = true;
dbData.lastBoxTime = iTime(dbData.symbol, PERIOD_CURRENT, 0);
// Draw the box
DrawDarvasBox();
if(DB_EnableLogging)
Print("DarvasBox: Box Formed - High: ", dbData.boxHigh, " Low: ", dbData.boxLow, " Time: ", dbData.lastBoxTime);
}
else
{
dbData.boxFormed = false;
// Delete box if it exists
ObjectsDeleteAll(0, dbData.boxName);
}
}
bool ValidateStopLevels(double price, double &sl, double &tp, ENUM_ORDER_TYPE orderType)
{
double minSlDistance = MathMax(dbData.minStopLevel, DB_StopLoss * dbData.point);
double minTpDistance = MathMax(dbData.minStopLevel, DB_TakeProfit * dbData.point);
if(orderType == ORDER_TYPE_BUY)
{
sl = price - minSlDistance;
tp = price + minTpDistance;
}
else
{
sl = price + minSlDistance;
tp = price - minTpDistance;
}
return true;
}
bool IsTrendFavorable(ENUM_ORDER_TYPE orderType)
{
if(!DB_UseTrendFilter)
return true;
double ma[];
ArraySetAsSeries(ma, true);
if(CopyBuffer(dbData.maHandle, 0, 0, 2, ma) <= 0)
return false;
double currentPrice = SymbolInfoDouble(dbData.symbol, SYMBOL_ASK);
double trendStrength = MathAbs(currentPrice - ma[0]) / dbData.point;
if(orderType == ORDER_TYPE_BUY)
return (currentPrice > ma[0] && trendStrength > DB_TrendThreshold);
else
return (currentPrice < ma[0] && trendStrength > DB_TrendThreshold);
}
bool CheckVolumeConditions()
{
if(!DB_UseVolumeSpikeFilter)
return true;
double volumes[];
ArraySetAsSeries(volumes, true);
if(CopyBuffer(dbData.volumeHandle, 0, 0, DB_VolumeMA_Period + 1, volumes) <= 0)
return false;
double volumeMA = 0;
for(int i = 1; i <= DB_VolumeMA_Period; i++)
volumeMA += volumes[i];
volumeMA /= DB_VolumeMA_Period;
double currentVolume = volumes[0];
if(volumeMA <= 0.0)
return (currentVolume > 0.0);
double volumeRatio = currentVolume / volumeMA;
return (volumeRatio > DB_VolumeThresholdMultiplier);
}
bool PlaceOrder(ENUM_ORDER_TYPE orderType, double price, double sl, double tp)
{
if(!ValidateStopLevels(price, sl, tp, orderType))
{
if(DB_EnableLogging)
Print("DarvasBox: Order rejected - Stop levels validation failed");
return false;
}
if(!IsTrendFavorable(orderType))
{
if(DB_EnableLogging)
Print("DarvasBox: Order rejected - Trend not favorable for ", EnumToString(orderType));
return false;
}
if(!CheckVolumeConditions())
{
if(DB_EnableLogging)
Print("DarvasBox: Order rejected - Volume conditions not met");
return false;
}
bool result = false;
const double lot = United_NormalizeVolume(dbData.symbol, DARVAS_TRADE_LOT);
if(lot <= 0.0)
{
Print("DarvasBox: Order rejected - invalid lot after normalize (raw=", DARVAS_TRADE_LOT, ")");
return false;
}
// Use market price (0) instead of explicit price - this ensures market order execution
// In backtesting, explicit price might fail if price has moved
if(orderType == ORDER_TYPE_BUY)
result = dbData.trade.Buy(lot, dbData.symbol, 0, sl, tp, "Darvas Box Breakout");
else
result = dbData.trade.Sell(lot, dbData.symbol, 0, sl, tp, "Darvas Box Breakdown");
// Always log errors, success only if logging enabled
if(result)
{
if(DB_EnableLogging)
Print("DarvasBox: ", (orderType == ORDER_TYPE_BUY ? "Buy" : "Sell"), " Order Placed Successfully");
}
else
{
// Always log failures with detailed info
uint retcode_uint = dbData.trade.ResultRetcode();
int retcode = (int)retcode_uint;
string desc = dbData.trade.ResultRetcodeDescription();
ulong deal = dbData.trade.ResultDeal();
ulong order = dbData.trade.ResultOrder();
Print("DarvasBox: ", (orderType == ORDER_TYPE_BUY ? "Buy" : "Sell"),
" Order Failed - Retcode: ", retcode,
", Description: ", desc,
", Deal: ", deal,
", Order: ", order,
", Symbol: ", dbData.symbol,
", Requested Price: ", price,
", SL: ", sl,
", TP: ", tp);
}
return result;
}
void ProcessDarvasBox(string symbol)
{
// Skip if not initialized (symbol not available)
if(!dbData.isInitialized)
return;
dbData.symbol = symbol; // Update symbol in case it changed
// Calculate new box levels - EXACTLY like original (called every tick)
CalculateDarvasBox();
// Check for trading signals - EXACTLY like original (checked every tick)
if(dbData.boxFormed)
{
double currentPrice = SymbolInfoDouble(dbData.symbol, SYMBOL_ASK);
long currentVolume_long = iVolume(dbData.symbol, PERIOD_H1, 0);
double currentVolume = (double)currentVolume_long;
if(DB_EnableLogging)
{
Print("DarvasBox: Current Price: ", currentPrice, " Box High: ", dbData.boxHigh, " Box Low: ", dbData.boxLow);
Print("DarvasBox: Current Volume: ", currentVolume, " Volume Threshold: ", DB_VolumeThreshold);
}
// Check for breakout above box - EXACTLY like original
if(currentPrice > dbData.boxHigh && currentVolume > DB_VolumeThreshold)
{
if(DB_EnableLogging)
Print("DarvasBox: Breakout Signal Detected - Price above box high");
// Buy signal
if(!PositionExistsByMagic(dbData.symbol, (ulong)DB_MagicNumber)) // No existing positions with our magic number
{
double sl = currentPrice - DB_StopLoss * dbData.point;
double tp = currentPrice + DB_TakeProfit * dbData.point;
if(DB_EnableLogging)
Print("DarvasBox: Preparing Buy Order - Price: ", currentPrice, " SL: ", sl, " TP: ", tp);
PlaceOrder(ORDER_TYPE_BUY, currentPrice, sl, tp);
}
else if(DB_EnableLogging)
Print("DarvasBox: Skipping Buy Signal - Position already exists");
}
// Check for breakdown below box - EXACTLY like original
if(currentPrice < dbData.boxLow && currentVolume > DB_VolumeThreshold)
{
if(DB_EnableLogging)
Print("DarvasBox: Breakdown Signal Detected - Price below box low");
// Sell signal
if(!PositionExistsByMagic(dbData.symbol, (ulong)DB_MagicNumber)) // No existing positions with our magic number
{
double sl = currentPrice + DB_StopLoss * dbData.point;
double tp = currentPrice - DB_TakeProfit * dbData.point;
if(DB_EnableLogging)
Print("DarvasBox: Preparing Sell Order - Price: ", currentPrice, " SL: ", sl, " TP: ", tp);
PlaceOrder(ORDER_TYPE_SELL, currentPrice, sl, tp);
}
else if(DB_EnableLogging)
Print("DarvasBox: Skipping Sell Signal - Position already exists");
}
}
else if(DB_EnableLogging)
Print("DarvasBox: No Box Formed - Waiting for consolidation");
}
//+------------------------------------------------------------------+
@@ -1,576 +0,0 @@
//+------------------------------------------------------------------+
//| EMASlopeDistanceStrategy.mqh |
//+------------------------------------------------------------------+
bool InitEMASlopeDistance(string symbol)
{
esData.symbol = symbol;
esData.letzte_überwachung_zeit = 0;
esData.überwachung_aktiv = false;
esData.preis_trigger_aktiv = false;
esData.steigung_trigger_aktiv = false;
esData.ticket = 0;
esData.trades_in_current_crossover = 0;
esData.crossover_detected = false;
esData.trade_open_time = 0;
esData.last_bar_time = 0;
esData.es_last_sl_adjust_success_time = 0;
// Check if symbol exists
if(!SymbolSelect(symbol, true))
{
Print("EMASlopeDistance: Symbol '", symbol, "' not available in Market Watch. Please add it to Market Watch or check symbol name.");
return false;
}
Sleep(100); // Wait for symbol to be ready
esData.trade.SetExpertMagicNumber(ES_MagicNumber);
esData.trade.SetDeviationInPoints(10);
esData.trade.SetTypeFilling(ORDER_FILLING_IOC);
esData.ema_handle = iMA(symbol, ES_Timeframe, ES_EMA_Periode, 0, MODE_EMA, PRICE_CLOSE);
if(esData.ema_handle == INVALID_HANDLE)
{
Print("EMASlopeDistance: Error creating EMA indicator for '", symbol, "'");
return false;
}
ArraySetAsSeries(esData.ema_array, true);
esData.isInitialized = true;
Print("EMASlopeDistance: Successfully initialized for symbol '", symbol, "'");
return true;
}
void DeinitEMASlopeDistance()
{
if(esData.ema_handle != INVALID_HANDLE)
IndicatorRelease(esData.ema_handle);
}
bool ES_IsWeeklyADXTrendFavorable(const ENUM_ORDER_TYPE order_type)
{
if(!ES_UseWeeklyADXFilter)
return true;
int adxShift = ES_WeeklyADXBarShift;
if(adxShift < 0)
adxShift = 0;
int adx_handle = iADX(esData.symbol, PERIOD_W1, ES_WeeklyADXPeriod);
if(adx_handle == INVALID_HANDLE)
return false;
double adx_buf[], plus_di_buf[], minus_di_buf[];
ArraySetAsSeries(adx_buf, true);
ArraySetAsSeries(plus_di_buf, true);
ArraySetAsSeries(minus_di_buf, true);
bool ok_adx = (CopyBuffer(adx_handle, 0, adxShift, 1, adx_buf) > 0);
bool ok_plus = (CopyBuffer(adx_handle, 1, adxShift, 1, plus_di_buf) > 0);
bool ok_minus = (CopyBuffer(adx_handle, 2, adxShift, 1, minus_di_buf) > 0);
IndicatorRelease(adx_handle);
if(!ok_adx || !ok_plus || !ok_minus)
return false;
double adx_value = adx_buf[0];
double plus_di = plus_di_buf[0];
double minus_di = minus_di_buf[0];
bool strength_ok = (adx_value >= ES_WeeklyADXMin);
bool direction_ok = true;
if(ES_WeeklyADXUseDirection)
{
if(order_type == ORDER_TYPE_BUY)
direction_ok = (plus_di > minus_di);
else
direction_ok = (minus_di > plus_di);
}
return strength_ok && direction_ok;
}
bool ES_TrailingActivationReached(const double position_profit, const ENUM_POSITION_TYPE position_type,
const double pips_multiplier)
{
if(ES_TrailingActivationPips <= 0.0)
return (position_profit > 0.0);
const double open_px = PositionGetDouble(POSITION_PRICE_OPEN);
if(position_type == POSITION_TYPE_BUY)
{
const double bid = SymbolInfoDouble(esData.symbol, SYMBOL_BID);
return ((bid - open_px) / SymbolInfoDouble(esData.symbol, SYMBOL_POINT) / pips_multiplier >= ES_TrailingActivationPips);
}
const double ask = SymbolInfoDouble(esData.symbol, SYMBOL_ASK);
return ((open_px - ask) / SymbolInfoDouble(esData.symbol, SYMBOL_POINT) / pips_multiplier >= ES_TrailingActivationPips);
}
//+------------------------------------------------------------------+
//| EMA Berechnung (EMA Calculation) |
//+------------------------------------------------------------------+
void BerechneEMA()
{
//--- EMA Werte vom Indicator kopieren (Copy EMA values from indicator)
int copied = CopyBuffer(esData.ema_handle, 0, 0, 3, esData.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]: ", esData.ema_array[0], " [1]: ", esData.ema_array[1], " [2]: ", esData.ema_array[2]);
}
//+------------------------------------------------------------------+
//| Trigger-Bedingungen prüfen (Check trigger conditions) |
//+------------------------------------------------------------------+
void PrüfeTrigger()
{
if(ArraySize(esData.ema_array) < 2)
{
Print("TRACE: Array zu klein - Größe: ", ArraySize(esData.ema_array));
return;
}
//--- Aktuelle Werte (Current values)
double aktueller_preis = SymbolInfoDouble(esData.symbol, SYMBOL_BID);
double aktueller_ask = SymbolInfoDouble(esData.symbol, SYMBOL_ASK);
double aktueller_close = iClose(esData.symbol, ES_Timeframe, 0);
int digits = (int)SymbolInfoInteger(esData.symbol, SYMBOL_DIGITS);
double point = SymbolInfoDouble(esData.symbol, SYMBOL_POINT);
double pips_multiplier = (digits == 3 || digits == 5) ? 10.0 : 1.0;
//--- EMA Werte in Variablen (EMA values in variables)
double ema_aktuell = esData.ema_array[0];
double ema_vorher = esData.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)
{
esData.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: ", ES_PreisSchwelle, ")");
Print("TRACE: Close: ", aktueller_close, " EMA: ", ema_aktuell);
Print("TRACE: Trades im aktuellen Crossover: ", esData.trades_in_current_crossover, "/", ES_MaxTradesPerCrossover);
if(preis_abstand > ES_PreisSchwelle && !esData.preis_trigger_aktiv)
{
esData.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: ", ES_SteigungSchwelle, ")");
if(MathAbs(steigung) > ES_SteigungSchwelle && !esData.steigung_trigger_aktiv)
{
esData.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(esData.preis_trigger_aktiv && esData.steigung_trigger_aktiv && !esData.überwachung_aktiv)
{
esData.überwachung_aktiv = true;
if(ES_UseBarData)
{
esData.letzte_überwachung_zeit = iTime(esData.symbol, ES_Timeframe, 0); // Aktuelle Bar-Zeit
Print("TRACE: Überwachung gestartet - Beide Trigger aktiv (Bar: ", TimeToString(esData.letzte_überwachung_zeit), ")");
}
else
{
esData.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(esData.ü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(esData.trades_in_current_crossover >= ES_MaxTradesPerCrossover)
{
Print("TRACE: Trade-Limit erreicht (", ES_MaxTradesPerCrossover, ") - Kein neuer Trade");
return;
}
if(bullish_signal && !PositionExistsByMagic(esData.symbol, (ulong)ES_MagicNumber))
{
if(!ES_IsWeeklyADXTrendFavorable(ORDER_TYPE_BUY))
{
Print("TRACE: Weekly ADX blockiert BUY-Entry");
return;
}
Print("TRACE: Versuche KAUF-Trade zu platzieren (Trade #", esData.trades_in_current_crossover + 1, ")");
if(PlatziereTrade(ORDER_TYPE_BUY))
{
esData.trades_in_current_crossover++;
}
}
else if(bearish_signal && !PositionExistsByMagic(esData.symbol, (ulong)ES_MagicNumber))
{
if(!ES_IsWeeklyADXTrendFavorable(ORDER_TYPE_SELL))
{
Print("TRACE: Weekly ADX blockiert SELL-Entry");
return;
}
Print("TRACE: Versuche VERKAUF-Trade zu platzieren (Trade #", esData.trades_in_current_crossover + 1, ")");
if(PlatziereTrade(ORDER_TYPE_SELL))
{
esData.trades_in_current_crossover++;
}
}
else if(PositionExistsByMagic(esData.symbol, (ulong)ES_MagicNumber))
{
Print("TRACE: Position bereits offen - kein neuer Trade");
}
}
}
//+------------------------------------------------------------------+
//| 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");
const double lot = United_NormalizeVolume(esData.symbol, g_ES_LotSize);
Print("TRACE: Lot (raw): ", g_ES_LotSize, " normalized: ", lot);
if(lot <= 0.0)
{
Print("TRACE: Abbruch — Lot nach Normalisierung ungültig");
return false;
}
bool success = false;
if(order_type == ORDER_TYPE_BUY)
{
success = esData.trade.Buy(lot, esData.symbol, 0, 0, 0, "EMA Crossover Trade");
}
else
{
success = esData.trade.Sell(lot, esData.symbol, 0, 0, 0, "EMA Crossover Trade");
}
if(success)
{
esData.ticket = (int)esData.trade.ResultOrder();
Print("TRACE: Trade erfolgreich platziert: ", (order_type == ORDER_TYPE_BUY) ? "KAUF" : "VERKAUF", " Ticket: ", esData.ticket);
//--- Trade-Öffnungszeit speichern (Save trade opening time)
esData.trade_open_time = iTime(esData.symbol, ES_Timeframe, 0);
esData.es_last_sl_adjust_success_time = 0;
Print("TRACE: Trade-Öffnungszeit: ", TimeToString(esData.trade_open_time));
//--- Überwachung zurücksetzen (Reset monitoring)
esData.überwachung_aktiv = false;
esData.preis_trigger_aktiv = false;
esData.steigung_trigger_aktiv = false;
return true;
}
else
{
Print("TRACE: Fehler beim Platzieren des Trades - Retcode: ", esData.trade.ResultRetcode());
Print("TRACE: Fehlerbeschreibung: ", esData.trade.ResultRetcodeDescription());
return false;
}
}
//+------------------------------------------------------------------+
//| Trades verwalten (Manage trades) |
//+------------------------------------------------------------------+
void VerwalteTrades()
{
if(!PositionSelectByMagic(esData.symbol, (ulong)ES_MagicNumber))
return;
if(ES_UseStaleStopLossExit && ES_StaleStopLossSeconds > 0)
{
const datetime stale_ref = (esData.es_last_sl_adjust_success_time > 0)
? esData.es_last_sl_adjust_success_time
: (datetime)PositionGetInteger(POSITION_TIME);
if(TimeCurrent() - stale_ref >= ES_StaleStopLossSeconds)
{
SchließePosition("Stale stop loss - keine SL-Anpassung");
return;
}
}
double position_profit = PositionGetDouble(POSITION_PROFIT);
ENUM_POSITION_TYPE position_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
int digits = (int)SymbolInfoInteger(esData.symbol, SYMBOL_DIGITS);
double point = SymbolInfoDouble(esData.symbol, SYMBOL_POINT);
double pips_multiplier = (digits == 3 || digits == 5) ? 10.0 : 1.0;
const double trail_dist = ES_TrailingStop * point * pips_multiplier;
const long stops_level = SymbolInfoInteger(esData.symbol, SYMBOL_TRADE_STOPS_LEVEL);
const double min_dist = (double)stops_level * point;
if(ES_UseTrailingStop && ES_TrailingStop > 0.0 && ES_TrailingActivationReached(position_profit, position_type, pips_multiplier))
{
if(position_type == POSITION_TYPE_BUY)
{
const double bid = SymbolInfoDouble(esData.symbol, SYMBOL_BID);
double new_stop_loss = NormalizeDouble(bid - trail_dist, digits);
if(min_dist > 0.0 && bid - new_stop_loss < min_dist)
new_stop_loss = NormalizeDouble(bid - min_dist, digits);
const double current_stop_loss = PositionGetDouble(POSITION_SL);
if(new_stop_loss < bid && new_stop_loss > 0.0 && new_stop_loss > current_stop_loss)
ÄndereStopLoss(new_stop_loss);
}
else if(position_type == POSITION_TYPE_SELL)
{
const double ask = SymbolInfoDouble(esData.symbol, SYMBOL_ASK);
double new_stop_loss = NormalizeDouble(ask + trail_dist, digits);
if(min_dist > 0.0 && new_stop_loss - ask < min_dist)
new_stop_loss = NormalizeDouble(ask + min_dist, digits);
const double current_stop_loss = PositionGetDouble(POSITION_SL);
if(new_stop_loss > ask && new_stop_loss > 0.0 &&
(new_stop_loss < current_stop_loss || current_stop_loss == 0.0))
ÄndereStopLoss(new_stop_loss);
}
}
//--- Ausstieg bei Preis unter/über EMA (Exit when price below/above EMA)
if(ArraySize(esData.ema_array) >= 1)
{
double aktueller_close = iClose(esData.symbol, ES_Timeframe, 0);
double ema_aktuell = esData.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 ", esData.trades_in_current_crossover);
}
}
//--- Profit-Prüfung nach X Bars (Profit check after X bars)
if(ES_CloseUnprofitableTrades && esData.trade_open_time != 0 && PositionExistsByMagic(esData.symbol, (ulong)ES_MagicNumber))
{
Print("TRACE: Profit-Prüfung aktiviert - CloseUnprofitableTrades: ", ES_CloseUnprofitableTrades);
PrüfeProfitNachBars();
}
else if(!ES_CloseUnprofitableTrades)
{
Print("TRACE: Profit-Prüfung deaktiviert - CloseUnprofitableTrades: ", ES_CloseUnprofitableTrades);
}
}
//+------------------------------------------------------------------+
//| Profit-Prüfung nach X Bars (Profit check after X bars) |
//+------------------------------------------------------------------+
void PrüfeProfitNachBars()
{
if(!PositionSelectByMagic(esData.symbol, (ulong)ES_MagicNumber))
{
return; // Keine Position offen
}
datetime current_bar_time = iTime(esData.symbol, ES_Timeframe, 0);
int bars_since_trade_open = iBarShift(esData.symbol, ES_Timeframe, esData.trade_open_time);
Print("TRACE: Bars seit Trade-Öffnung: ", bars_since_trade_open, "/", ES_ProfitCheckBars);
//--- Prüfe ob genügend Bars vergangen sind (Check if enough bars have passed)
if(bars_since_trade_open >= ES_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 ", ES_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)
esData.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)
esData.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 = ModifyPositionByMagic(esData.trade, esData.symbol, (ulong)ES_MagicNumber, new_stop_loss, PositionGetDouble(POSITION_TP));
if(success)
{
esData.es_last_sl_adjust_success_time = TimeCurrent();
Print("TRACE: Stop Loss erfolgreich geändert auf: ", new_stop_loss);
}
else
{
Print("TRACE: Fehler beim Ändern des Stop Loss - Retcode: ", esData.trade.ResultRetcode());
Print("TRACE: Fehlerbeschreibung: ", esData.trade.ResultRetcodeDescription());
}
}
//+------------------------------------------------------------------+
//| Position schließen (Close position) |
//+------------------------------------------------------------------+
void SchließePosition(string reason = "Unbekannt")
{
Print("TRACE: Versuche Position zu schließen - Grund: ", reason);
bool success = ClosePositionByMagic(esData.trade, esData.symbol, (ulong)ES_MagicNumber);
if(success)
{
esData.es_last_sl_adjust_success_time = 0;
Print("TRACE: Position erfolgreich geschlossen - Grund: ", reason);
}
else
{
Print("TRACE: Fehler beim Schließen der Position - Retcode: ", esData.trade.ResultRetcode());
Print("TRACE: Fehlerbeschreibung: ", esData.trade.ResultRetcodeDescription());
}
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void ProcessEMASlopeDistance(string symbol)
{
if(!esData.isInitialized)
return;
esData.symbol = symbol;
const datetime current_bar_time = iTime(esData.symbol, ES_Timeframe, 0);
const bool new_bar = (current_bar_time != esData.last_bar_time);
const bool has_position = PositionExistsByMagic(esData.symbol, (ulong)ES_MagicNumber);
if(ES_UseBarData && !new_bar && !has_position)
return;
if(new_bar)
esData.last_bar_time = current_bar_time;
BerechneEMA();
const bool run_signals = (!ES_UseBarData || new_bar);
if(run_signals && ArraySize(esData.ema_array) > 0)
{
double aktueller_close = iClose(esData.symbol, ES_Timeframe, 0);
double ema_aktuell = esData.ema_array[0];
double ema_vorher = esData.ema_array[1];
double point = SymbolInfoDouble(esData.symbol, SYMBOL_POINT);
double preis_abstand = MathAbs(aktueller_close - ema_aktuell) / point;
double steigung = (ema_aktuell - ema_vorher) / point;
if(ES_UseBarData)
{
Print("=== DEBUG INFO (Neuer Bar) ===");
Print("Bar Zeit: ", TimeToString(iTime(esData.symbol, ES_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: ", esData.preis_trigger_aktiv, " Steigungs-Trigger: ", esData.steigung_trigger_aktiv);
Print("Überwachung aktiv: ", esData.überwachung_aktiv);
Print("Position offen: ", PositionExistsByMagic(esData.symbol, (ulong)ES_MagicNumber));
Print("Trades im aktuellen Crossover: ", esData.trades_in_current_crossover, "/", ES_MaxTradesPerCrossover);
Print("==================");
}
if(run_signals)
{
if(esData.überwachung_aktiv)
{
if(ES_UseBarData)
{
int bars_since_monitoring = iBarShift(esData.symbol, ES_Timeframe, esData.letzte_überwachung_zeit);
int timeout_bars = (int)(ES_ÜberwachungTimeout / PeriodSeconds(ES_Timeframe));
if(bars_since_monitoring > timeout_bars)
{
esData.überwachung_aktiv = false;
esData.preis_trigger_aktiv = false;
esData.steigung_trigger_aktiv = false;
Print("Überwachung beendet - Bar-basierte Zeitüberschreitung (", bars_since_monitoring, " Bars)");
}
}
else
{
if(TimeCurrent() - esData.letzte_überwachung_zeit > ES_ÜberwachungTimeout)
{
esData.überwachung_aktiv = false;
esData.preis_trigger_aktiv = false;
esData.steigung_trigger_aktiv = false;
Print("Überwachung beendet - Tick-basierte Zeitüberschreitung");
}
}
}
PrüfeTrigger();
}
VerwalteTrades();
}
//+------------------------------------------------------------------+
@@ -1,387 +0,0 @@
//+------------------------------------------------------------------+
//| RSIConsolidationStrategy.mqh |
//| Ported from cluster-0/RSIConsolidation/RSIConsolidation.mq5 |
//+------------------------------------------------------------------+
#ifndef RSI_CONSOLIDATION_STRATEGY_MQH
#define RSI_CONSOLIDATION_STRATEGY_MQH
struct RSIConsolidationData
{
string symbol;
bool isInitialized;
CTrade trade;
ENUM_TIMEFRAMES signalTF;
bool entryOnNewBarOnly;
int adxPeriod;
double adxMax;
bool useATRRatioFilter;
int atrPeriod;
int atrSmaPeriod;
double atrRatioMax;
bool useFlatEMAFilter;
int emaFast;
int emaSlow;
double emaSeparationMaxPct;
int rsiPeriod;
ENUM_APPLIED_PRICE rsiPrice;
double rsiOversold;
double rsiOverbought;
bool useRSIMeanExit;
double rsiExitLong;
double rsiExitShort;
double slAtrMult;
double tpAtrMult;
int maxBarsInTrade;
ulong magic;
int slippage;
int maxSpreadPoints;
int h_rsi;
int h_adx;
int h_atr;
int h_ema_fast;
int h_ema_slow;
datetime lastBar;
};
bool RCO_Copy1(const int handle, double &v)
{
double b[];
ArraySetAsSeries(b, true);
if(CopyBuffer(handle, 0, 0, 1, b) < 1)
return false;
v = b[0];
return true;
}
bool RCO_RsiBuffers(RSIConsolidationData &d, double &cur, double &prev, double &twoAgo)
{
double b[];
ArraySetAsSeries(b, true);
if(CopyBuffer(d.h_rsi, 0, 0, 3, b) < 3)
return false;
cur = b[0];
prev = b[1];
twoAgo = b[2];
return true;
}
double RCO_NormalizeVolume(const string sym, double vol)
{
double minLot = SymbolInfoDouble(sym, SYMBOL_VOLUME_MIN);
double maxLot = SymbolInfoDouble(sym, SYMBOL_VOLUME_MAX);
double step = SymbolInfoDouble(sym, SYMBOL_VOLUME_STEP);
if(step > 0.0)
vol = MathFloor(vol / step) * step;
if(vol < minLot)
vol = minLot;
if(vol > maxLot)
vol = maxLot;
return vol;
}
int RCO_CurrentSpreadPoints(const string sym)
{
long spread = 0;
if(!SymbolInfoInteger(sym, SYMBOL_SPREAD, spread))
return 999999;
return (int)spread;
}
double RCO_MinStopsDistancePrice(const string sym)
{
long lvl = 0;
if(!SymbolInfoInteger(sym, SYMBOL_TRADE_STOPS_LEVEL, lvl))
return 0;
double pt = SymbolInfoDouble(sym, SYMBOL_POINT);
if(pt <= 0)
return 0;
return (double)lvl * pt;
}
bool RCO_RegimeIsConsolidation(RSIConsolidationData &d)
{
double adx = 0;
if(!RCO_Copy1(d.h_adx, adx))
return false;
if(adx >= d.adxMax)
return false;
if(d.useATRRatioFilter)
{
double atrArr[];
ArraySetAsSeries(atrArr, true);
if(CopyBuffer(d.h_atr, 0, 0, d.atrSmaPeriod + 1, atrArr) < d.atrSmaPeriod + 1)
return false;
double sum = 0;
for(int i = 1; i <= d.atrSmaPeriod; i++)
sum += atrArr[i];
double smaAtr = sum / (double)d.atrSmaPeriod;
if(smaAtr <= 0.0)
return false;
double ratio = atrArr[0] / smaAtr;
if(ratio > d.atrRatioMax)
return false;
}
if(d.useFlatEMAFilter)
{
double ef[], es[];
ArraySetAsSeries(ef, true);
ArraySetAsSeries(es, true);
if(CopyBuffer(d.h_ema_fast, 0, 0, 1, ef) < 1)
return false;
if(CopyBuffer(d.h_ema_slow, 0, 0, 1, es) < 1)
return false;
double c = SymbolInfoDouble(d.symbol, SYMBOL_BID);
if(c <= 0)
return false;
double sep = MathAbs(ef[0] - es[0]) / c * 100.0;
if(sep > d.emaSeparationMaxPct)
return false;
}
return true;
}
bool RCO_EntryBuyCross(RSIConsolidationData &d, const double twoAgo, const double prev)
{
return (twoAgo <= d.rsiOversold && prev > d.rsiOversold);
}
bool RCO_EntrySellCross(RSIConsolidationData &d, const double twoAgo, const double prev)
{
return (twoAgo >= d.rsiOverbought && prev < d.rsiOverbought);
}
void RCO_TryCloseByRSI(RSIConsolidationData &d, const ENUM_POSITION_TYPE typ, const double rsi)
{
ulong tk = GetPositionTicketByMagic(d.symbol, d.magic);
if(tk == 0 || !PositionSelectByTicketSymbolAndMagic(tk, d.symbol, d.magic))
return;
if(!d.useRSIMeanExit)
return;
if(typ == POSITION_TYPE_BUY && rsi >= d.rsiExitLong)
d.trade.PositionClose(tk);
else if(typ == POSITION_TYPE_SELL && rsi <= d.rsiExitShort)
d.trade.PositionClose(tk);
}
void RCO_ManageOpenPosition(RSIConsolidationData &d, const double rsi)
{
ulong tk = GetPositionTicketByMagic(d.symbol, d.magic);
if(tk == 0 || !PositionSelectByTicketSymbolAndMagic(tk, d.symbol, d.magic))
return;
ENUM_POSITION_TYPE typ = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
datetime openT = (datetime)PositionGetInteger(POSITION_TIME);
int barsAgo = iBarShift(d.symbol, d.signalTF, openT, false);
if(barsAgo >= 0 && barsAgo >= d.maxBarsInTrade)
{
d.trade.PositionClose(tk);
return;
}
RCO_TryCloseByRSI(d, typ, rsi);
}
bool InitRSIConsolidation(RSIConsolidationData &d,
const string inpSymbol,
const ENUM_TIMEFRAMES signalTF,
const bool entryOnNewBarOnly,
const int adxPeriod,
const double adxMax,
const bool useATRRatioFilter,
const int atrPeriod,
const int atrSmaPeriod,
const double atrRatioMax,
const bool useFlatEMAFilter,
const int emaFast,
const int emaSlow,
const double emaSeparationMaxPct,
const int rsiPeriod,
const ENUM_APPLIED_PRICE rsiPrice,
const double rsiOversold,
const double rsiOverbought,
const bool useRSIMeanExit,
const double rsiExitLong,
const double rsiExitShort,
const double slAtrMult,
const double tpAtrMult,
const int maxBarsInTrade,
const ulong magic,
const int slippage,
const int maxSpreadPoints)
{
d.isInitialized = false;
d.symbol = inpSymbol;
StringTrimLeft(d.symbol);
StringTrimRight(d.symbol);
if(StringLen(d.symbol) == 0)
d.symbol = _Symbol;
d.signalTF = signalTF;
d.entryOnNewBarOnly = entryOnNewBarOnly;
d.adxPeriod = adxPeriod;
d.adxMax = adxMax;
d.useATRRatioFilter = useATRRatioFilter;
d.atrPeriod = atrPeriod;
d.atrSmaPeriod = atrSmaPeriod;
d.atrRatioMax = atrRatioMax;
d.useFlatEMAFilter = useFlatEMAFilter;
d.emaFast = emaFast;
d.emaSlow = emaSlow;
d.emaSeparationMaxPct = emaSeparationMaxPct;
d.rsiPeriod = rsiPeriod;
d.rsiPrice = rsiPrice;
d.rsiOversold = rsiOversold;
d.rsiOverbought = rsiOverbought;
d.useRSIMeanExit = useRSIMeanExit;
d.rsiExitLong = rsiExitLong;
d.rsiExitShort = rsiExitShort;
d.slAtrMult = slAtrMult;
d.tpAtrMult = tpAtrMult;
d.maxBarsInTrade = maxBarsInTrade;
d.magic = magic;
d.slippage = slippage;
d.maxSpreadPoints = maxSpreadPoints;
d.lastBar = 0;
d.h_rsi = INVALID_HANDLE;
d.h_adx = INVALID_HANDLE;
d.h_atr = INVALID_HANDLE;
d.h_ema_fast = INVALID_HANDLE;
d.h_ema_slow = INVALID_HANDLE;
d.isInitialized = false;
if(!SymbolSelect(d.symbol, true))
{
Print("RSIConsolidation: SymbolSelect failed: ", d.symbol);
return false;
}
d.trade.SetExpertMagicNumber((long)d.magic);
d.trade.SetDeviationInPoints(d.slippage);
d.trade.SetTypeFillingBySymbol(d.symbol);
d.h_rsi = iRSI(d.symbol, d.signalTF, d.rsiPeriod, d.rsiPrice);
d.h_adx = iADX(d.symbol, d.signalTF, d.adxPeriod);
d.h_atr = iATR(d.symbol, d.signalTF, d.atrPeriod);
d.h_ema_fast = iMA(d.symbol, d.signalTF, d.emaFast, 0, MODE_EMA, PRICE_CLOSE);
d.h_ema_slow = iMA(d.symbol, d.signalTF, d.emaSlow, 0, MODE_EMA, PRICE_CLOSE);
if(d.h_rsi == INVALID_HANDLE || d.h_adx == INVALID_HANDLE || d.h_atr == INVALID_HANDLE
|| d.h_ema_fast == INVALID_HANDLE || d.h_ema_slow == INVALID_HANDLE)
{
Print("RSIConsolidation: indicator init failed");
DeinitRSIConsolidation(d);
return false;
}
d.isInitialized = true;
Print("RSIConsolidation: symbol=", d.symbol, " TF=", EnumToString(d.signalTF));
return true;
}
void DeinitRSIConsolidation(RSIConsolidationData &d)
{
if(d.h_rsi != INVALID_HANDLE)
IndicatorRelease(d.h_rsi);
if(d.h_adx != INVALID_HANDLE)
IndicatorRelease(d.h_adx);
if(d.h_atr != INVALID_HANDLE)
IndicatorRelease(d.h_atr);
if(d.h_ema_fast != INVALID_HANDLE)
IndicatorRelease(d.h_ema_fast);
if(d.h_ema_slow != INVALID_HANDLE)
IndicatorRelease(d.h_ema_slow);
d.h_rsi = INVALID_HANDLE;
d.h_adx = INVALID_HANDLE;
d.h_atr = INVALID_HANDLE;
d.h_ema_fast = INVALID_HANDLE;
d.h_ema_slow = INVALID_HANDLE;
d.isInitialized = false;
}
bool RCO_EnoughHistory(RSIConsolidationData &d)
{
int need = MathMax(d.rsiPeriod + 3, MathMax(d.adxPeriod + 2, d.atrSmaPeriod + 3));
if(Bars(d.symbol, d.signalTF) < need)
return false;
return true;
}
void ProcessRSIConsolidation(RSIConsolidationData &d, const double lots)
{
if(!d.isInitialized)
return;
if(!RCO_EnoughHistory(d))
return;
if(d.maxSpreadPoints > 0 && RCO_CurrentSpreadPoints(d.symbol) > d.maxSpreadPoints)
return;
double rsi, rsiPrev, rsi2;
if(!RCO_RsiBuffers(d, rsi, rsiPrev, rsi2))
return;
datetime barTime = iTime(d.symbol, d.signalTF, 0);
bool isNew = (barTime != d.lastBar);
if(PositionExistsByMagic(d.symbol, d.magic))
{
RCO_ManageOpenPosition(d, rsi);
if(isNew)
d.lastBar = barTime;
return;
}
if(d.entryOnNewBarOnly && !isNew)
return;
d.lastBar = barTime;
if(!RCO_RegimeIsConsolidation(d))
return;
double atrArr[];
ArraySetAsSeries(atrArr, true);
if(CopyBuffer(d.h_atr, 0, 0, 1, atrArr) < 1)
return;
double atr = atrArr[0];
int dig = (int)SymbolInfoInteger(d.symbol, SYMBOL_DIGITS);
double slDist = atr * d.slAtrMult;
double tpDist = atr * d.tpAtrMult;
double minD = RCO_MinStopsDistancePrice(d.symbol);
if(slDist < minD)
slDist = minD;
if(tpDist < minD)
tpDist = minD;
double vol = RCO_NormalizeVolume(d.symbol, lots);
if(RCO_EntryBuyCross(d, rsi2, rsiPrev))
{
if(!United_MayOpenNewEntry(d.symbol, d.magic, true))
return;
double ask = SymbolInfoDouble(d.symbol, SYMBOL_ASK);
double sl = ask - slDist;
double tp = ask + tpDist;
sl = NormalizeDouble(sl, dig);
tp = NormalizeDouble(tp, dig);
if(!d.trade.Buy(vol, d.symbol, ask, sl, tp, "RSIConsolidation BUY"))
Print("RSIConsolidation BUY failed | retcode=", d.trade.ResultRetcode(), " ", d.trade.ResultRetcodeDescription());
}
else if(RCO_EntrySellCross(d, rsi2, rsiPrev))
{
if(!United_MayOpenNewEntry(d.symbol, d.magic, false))
return;
double bid = SymbolInfoDouble(d.symbol, SYMBOL_BID);
double sl = bid + slDist;
double tp = bid - tpDist;
sl = NormalizeDouble(sl, dig);
tp = NormalizeDouble(tp, dig);
if(!d.trade.Sell(vol, d.symbol, bid, sl, tp, "RSIConsolidation SELL"))
Print("RSIConsolidation SELL failed | retcode=", d.trade.ResultRetcode(), " ", d.trade.ResultRetcodeDescription());
}
}
#endif // RSI_CONSOLIDATION_STRATEGY_MQH
@@ -1,269 +0,0 @@
//+------------------------------------------------------------------+
//| RSICrossOverReversalStrategy.mqh |
//+------------------------------------------------------------------+
void WeekDays_Init()
{
rcData.WeekDays[0] = RC_Sunday;
rcData.WeekDays[1] = RC_Monday;
rcData.WeekDays[2] = RC_Tuesday;
rcData.WeekDays[3] = RC_Wednesday;
rcData.WeekDays[4] = RC_Thursday;
rcData.WeekDays[5] = RC_Friday;
rcData.WeekDays[6] = RC_Saturday;
}
bool WeekDays_Check(datetime aTime)
{
MqlDateTime stm;
TimeToStruct(aTime, stm);
return(rcData.WeekDays[stm.day_of_week]);
}
bool RC_HourInWindow(const int h, const int beginRaw, const int endRaw)
{
const int b = beginRaw % 24;
const int e = endRaw % 24;
if(b == e)
return false;
if(b < e)
return (h >= b && h < e);
return (h >= b || h < e);
}
bool RC_TradingHoursAllow(const int currentHour)
{
return RC_HourInWindow(currentHour, RC_tradingHourOneBegin, RC_tradingHourOneEnd)
|| RC_HourInWindow(currentHour, RC_tradingHourTwoBegin, RC_tradingHourTwoEnd);
}
int TimeHour(datetime when = 0)
{
if(when == 0) when = TimeCurrent();
MqlDateTime dt;
TimeToStruct(when, dt);
return dt.hour;
}
bool InitRSICrossOverReversal(string symbol)
{
WeekDays_Init();
rcData.symbol = symbol;
rcData.previousRSIDef = 0;
rcData.lastTradeTime = 0;
rcData.bartime = 0;
rcData.lastBarTime = 0;
// Check if symbol exists
if(!SymbolSelect(symbol, true))
{
Print("RSICrossOverReversal: Symbol '", symbol, "' not available in Market Watch. Please add it to Market Watch or check symbol name.");
return false;
}
Sleep(100); // Wait for symbol to be ready
rcData.rsiHandle = iRSI(symbol, RC_TimeFrame1, RC_rsiPeriod, PRICE_CLOSE);
if(rcData.rsiHandle == INVALID_HANDLE)
{
Print("RSICrossOverReversal: Error creating RSI handle for '", symbol, "'");
return false;
}
rcData.emaHandle = iMA(symbol, RC_TimeFrame2, RC_emaPeriod, 0, MODE_EMA, PRICE_CLOSE);
if(rcData.emaHandle == INVALID_HANDLE)
{
Print("RSICrossOverReversal: Error creating EMA handle for '", symbol, "'");
return false;
}
rcData.trade.SetExpertMagicNumber(RC_MagicNumber);
rcData.trade.SetDeviationInPoints(RC_slippage);
rcData.isInitialized = true;
Print("RSICrossOverReversal: Successfully initialized for symbol '", symbol, "'");
return true;
}
void DeinitRSICrossOverReversal()
{
if(rcData.rsiHandle != INVALID_HANDLE)
IndicatorRelease(rcData.rsiHandle);
if(rcData.emaHandle != INVALID_HANDLE)
IndicatorRelease(rcData.emaHandle);
}
void Close_Position_MN(ulong magicNumber)
{
ClosePositionByMagic(rcData.trade, rcData.symbol, (int)magicNumber);
}
void ApplyTrailingStop()
{
if(!PositionSelectByMagic(rcData.symbol, RC_MagicNumber))
return;
ulong PositionTicket = PositionGetInteger(POSITION_TICKET);
ENUM_POSITION_TYPE trade_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
string symbol = rcData.symbol;
double POINT = SymbolInfoDouble(symbol, SYMBOL_POINT);
int DIGIT = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
if(trade_type == POSITION_TYPE_BUY)
{
double Bid = NormalizeDouble(SymbolInfoDouble(symbol, SYMBOL_BID), DIGIT);
if(Bid - PositionGetDouble(POSITION_PRICE_OPEN) > NormalizeDouble(POINT * RC_TrailingStop, DIGIT))
{
if(PositionGetDouble(POSITION_SL) < NormalizeDouble(Bid - POINT * RC_TrailingStop, DIGIT))
{
ModifyPositionByMagic(rcData.trade, symbol, RC_MagicNumber,
NormalizeDouble(Bid - POINT * RC_TrailingStop, DIGIT),
PositionGetDouble(POSITION_TP));
}
}
}
else if(trade_type == POSITION_TYPE_SELL)
{
double Ask = NormalizeDouble(SymbolInfoDouble(symbol, SYMBOL_ASK), DIGIT);
if((PositionGetDouble(POSITION_PRICE_OPEN) - Ask) > NormalizeDouble(POINT * RC_TrailingStop, DIGIT))
{
if((PositionGetDouble(POSITION_SL) > NormalizeDouble(Ask + POINT * RC_TrailingStop, DIGIT)) ||
(PositionGetDouble(POSITION_SL) == 0))
{
ModifyPositionByMagic(rcData.trade, symbol, RC_MagicNumber,
NormalizeDouble(Ask + POINT * RC_TrailingStop, DIGIT),
PositionGetDouble(POSITION_TP));
}
}
}
}
void ProcessRSICrossOverReversal(string symbol)
{
// Skip if not initialized (symbol not available)
if(!rcData.isInitialized)
return;
rcData.symbol = symbol; // Update symbol in case it changed
if(rcData.bartime == iTime(rcData.symbol, RC_BarTimeFrame, 0))
return;
rcData.bartime = iTime(rcData.symbol, RC_BarTimeFrame, 0);
double rsi[];
if(CopyBuffer(rcData.rsiHandle, 0, 0, 2, rsi) <= 0)
return;
double ema[];
if(CopyBuffer(rcData.emaHandle, 0, 0, 2, ema) <= 0)
return;
datetime currentTime = TimeCurrent();
int currentHour = TimeHour(TimeCurrent());
if(!WeekDays_Check(TimeTradeServer()))
{
Close_Position_MN(RC_MagicNumber);
return;
}
if(!RC_TradingHoursAllow(currentHour))
{
Close_Position_MN(RC_MagicNumber);
return;
}
bool hasPosition = PositionExistsByMagic(rcData.symbol, RC_MagicNumber);
double currentRSI = rsi[0];
double previousRSI = rsi[1];
if(rcData.previousRSIDef == 0)
{
rcData.previousRSIDef = currentRSI;
return;
}
double currentEMA = ema[0];
double previousEMA = ema[1];
double emaSlope = (currentEMA - previousEMA) * 100;
const double closeCurr = iClose(rcData.symbol, RC_TimeFrame1, 0);
// Raw (close-EMA)*10 blows past threshold on XAUUSD (~2600) almost every bar — blocks all entries.
// Compare distance in pips so RC_emaDistanceThreshold matches intent across symbols.
const double point = SymbolInfoDouble(rcData.symbol, SYMBOL_POINT);
const int symDig = (int)SymbolInfoInteger(rcData.symbol, SYMBOL_DIGITS);
const double pipMult = (symDig == 3 || symDig == 5) ? 10.0 : 1.0;
const double pipSize = (point > 0.0 ? point * pipMult : point);
const double priceToEmaPips = (pipSize > 0.0 ? MathAbs(closeCurr - currentEMA) / pipSize : 0.0);
bool isBuyPosition = false;
bool isSellPosition = false;
if(hasPosition)
{
if(PositionSelectByMagic(rcData.symbol, RC_MagicNumber))
{
ENUM_POSITION_TYPE positionType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(positionType == POSITION_TYPE_BUY)
isBuyPosition = true;
else if(positionType == POSITION_TYPE_SELL)
isSellPosition = true;
}
}
ApplyTrailingStop();
bool cooldownPassed = (currentTime - rcData.lastTradeTime) >= RC_cooldownSeconds;
const bool isTrendStrong = RC_UseTrendStrengthFilter &&
(MathAbs(emaSlope) > RC_emaSlopeThreshold || priceToEmaPips > RC_emaDistanceThreshold);
if(isBuyPosition && currentRSI > RC_exitBuyRSI)
{
Close_Position_MN(RC_MagicNumber);
rcData.lastTradeTime = currentTime;
}
if(isSellPosition && currentRSI < RC_exitSellRSI)
{
Close_Position_MN(RC_MagicNumber);
rcData.lastTradeTime = currentTime;
}
if(isTrendStrong)
{
Close_Position_MN(RC_MagicNumber);
rcData.lastTradeTime = currentTime;
}
if(!isTrendStrong &&
currentRSI < RC_overboughtLevel - RC_entryRSISellSpread && rcData.previousRSIDef >= RC_overboughtLevel &&
!isSellPosition && !hasPosition && cooldownPassed)
{
const double vol = United_NormalizeVolume(rcData.symbol, g_RC_LotSize);
if(vol > 0.0)
{
rcData.trade.SetExpertMagicNumber(RC_MagicNumber);
if(rcData.trade.Sell(vol, rcData.symbol, 0.0, 0.0, 0.0, "Sell Order"))
rcData.lastTradeTime = currentTime;
}
}
if(!isTrendStrong &&
currentRSI > RC_oversoldLevel + RC_entryRSIBuySpread && rcData.previousRSIDef <= RC_oversoldLevel &&
!isBuyPosition && !hasPosition && cooldownPassed)
{
const double vol = United_NormalizeVolume(rcData.symbol, g_RC_LotSize);
if(vol > 0.0)
{
rcData.trade.SetExpertMagicNumber(RC_MagicNumber);
if(rcData.trade.Buy(vol, rcData.symbol, 0.0, 0.0, 0.0, "Buy Order"))
rcData.lastTradeTime = currentTime;
}
}
rcData.previousRSIDef = currentRSI;
}
//+------------------------------------------------------------------+
@@ -1,492 +0,0 @@
//+------------------------------------------------------------------+
//| RSIMidPointHijackStrategy.mqh |
//+------------------------------------------------------------------+
double RM_NormalizedLot(const string sym)
{
return United_NormalizeVolume(sym, g_RM_LotSize);
}
bool IsNewBar(string symbol)
{
datetime time[];
if(CopyTime(symbol, RM_InpTimeframe, 0, 1, time) > 0)
{
if(time[0] != rmData.lastBarTime)
{
rmData.lastBarTime = time[0];
return true;
}
}
return false;
}
bool IsWithinTradingHours(int startHour, int endHour)
{
MqlDateTime currentTime;
TimeToStruct(TimeCurrent(), currentTime);
if(startHour <= endHour)
return (currentTime.hour >= startHour && currentTime.hour < endHour);
else
return (currentTime.hour >= startHour || currentTime.hour < endHour);
}
bool HasPosition(string symbol, int magic)
{
return PositionExistsByMagic(symbol, magic);
}
bool HasProfitablePosition(int excludeMagic)
{
bool hasProfitable = false;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(rmData.positionInfo.SelectByIndex(i))
{
if(rmData.positionInfo.Magic() != excludeMagic)
{
double profit = rmData.positionInfo.Profit();
if(profit > RM_InpLockProfitThreshold * _Point)
{
hasProfitable = true;
if(RM_InpCloseOppositeTrades)
{
if((excludeMagic == RM_InpMagicNumberRSIFollow && rmData.positionInfo.Magic() == RM_InpMagicNumberRSIReverse) ||
(excludeMagic == RM_InpMagicNumberRSIReverse && rmData.positionInfo.Magic() == RM_InpMagicNumberRSIFollow) ||
(excludeMagic == RM_InpMagicNumberEMACross && (rmData.positionInfo.Magic() == RM_InpMagicNumberRSIReverse || rmData.positionInfo.Magic() == RM_InpMagicNumberRSIFollow)) ||
((excludeMagic == RM_InpMagicNumberRSIFollow || excludeMagic == RM_InpMagicNumberRSIReverse) && rmData.positionInfo.Magic() == RM_InpMagicNumberEMACross))
{
ClosePosition(rmData.symbol, (int)rmData.positionInfo.Magic());
}
}
}
}
}
}
return hasProfitable;
}
bool IsRSIReverseInCooldown(string symbol)
{
if(RM_InpRSIReverseCooldownBars <= 0)
return false;
if(!rmData.rsiReverseInCooldown)
return false;
datetime time[];
if(CopyTime(symbol, RM_InpTimeframe, 0, 1, time) > 0)
{
datetime currentBarTime = time[0];
datetime cooldownEndTime = rmData.rsiReverseLastCloseTime + RM_InpRSIReverseCooldownBars * PeriodSeconds(RM_InpTimeframe);
if(currentBarTime >= cooldownEndTime)
{
rmData.rsiReverseInCooldown = false;
return false;
}
}
return true;
}
void CheckRSIFollowStrategy(string symbol)
{
if(!IsWithinTradingHours(RM_InpRSIFollowStartHour, RM_InpRSIFollowEndHour))
{
if(RM_InpRSIFollowCloseOutsideHours)
{
if(HasPosition(symbol, RM_InpMagicNumberRSIFollow))
ClosePosition(symbol, RM_InpMagicNumberRSIFollow);
}
return;
}
if(RM_InpEnableStrategyLock && HasProfitablePosition(RM_InpMagicNumberRSIFollow))
return;
if(rmData.lastBarRSI > RM_InpRSIOverbought)
rmData.rsiOverbought = true;
else if(rmData.lastBarRSI < RM_InpRSIOversold)
rmData.rsiOversold = true;
if(rmData.rsiOverbought && rmData.lastBarRSI < RM_InpRSIExitLevel)
{
if(!HasPosition(symbol, RM_InpMagicNumberRSIFollow))
{
rmData.trade.SetExpertMagicNumber(RM_InpMagicNumberRSIFollow);
const double vol = RM_NormalizedLot(symbol);
if(vol > 0.0)
rmData.trade.Sell(vol, symbol, 0, 0, 0, "RSI Follow");
}
rmData.rsiOverbought = false;
}
else if(rmData.rsiOversold && rmData.lastBarRSI > RM_InpRSIExitLevel)
{
if(!HasPosition(symbol, RM_InpMagicNumberRSIFollow))
{
rmData.trade.SetExpertMagicNumber(RM_InpMagicNumberRSIFollow);
const double vol = RM_NormalizedLot(symbol);
if(vol > 0.0)
rmData.trade.Buy(vol, symbol, 0, 0, 0, "RSI Follow");
}
rmData.rsiOversold = false;
}
}
void CheckRSIReverseStrategy(string symbol)
{
if(!IsWithinTradingHours(RM_InpRSIReverseStartHour, RM_InpRSIReverseEndHour))
{
if(RM_InpRSIReverseCloseOutsideHours)
{
if(HasPosition(symbol, RM_InpMagicNumberRSIReverse))
ClosePosition(symbol, RM_InpMagicNumberRSIReverse);
}
return;
}
if(RM_InpEnableStrategyLock && HasProfitablePosition(RM_InpMagicNumberRSIReverse))
return;
if(IsRSIReverseInCooldown(symbol))
return;
if(rmData.lastBarRSIReverse > RM_InpRSIReverseOverbought)
rmData.rsiReverseOverbought = true;
else if(rmData.lastBarRSIReverse < RM_InpRSIReverseOversold)
rmData.rsiReverseOversold = true;
if(rmData.rsiReverseOverbought && rmData.lastBarRSIReverse < RM_InpRSIReverseCrossLevel)
{
if(!HasPosition(symbol, RM_InpMagicNumberRSIReverse))
{
rmData.trade.SetExpertMagicNumber(RM_InpMagicNumberRSIReverse);
const double vol = RM_NormalizedLot(symbol);
if(vol > 0.0)
rmData.trade.Sell(vol, symbol, 0, 0, 0, "RSI Reverse");
}
rmData.rsiReverseOverbought = false;
}
else if(rmData.rsiReverseOversold && rmData.lastBarRSIReverse > RM_InpRSIReverseCrossLevel)
{
if(!HasPosition(symbol, RM_InpMagicNumberRSIReverse))
{
rmData.trade.SetExpertMagicNumber(RM_InpMagicNumberRSIReverse);
const double vol = RM_NormalizedLot(symbol);
if(vol > 0.0)
rmData.trade.Buy(vol, symbol, 0, 0, 0, "RSI Reverse");
}
rmData.rsiReverseOversold = false;
}
}
void CheckEMACrossStrategy(string symbol)
{
if(!IsWithinTradingHours(RM_InpEMACrossStartHour, RM_InpEMACrossEndHour))
{
if(RM_InpEMACrossCloseOutsideHours)
{
if(HasPosition(symbol, RM_InpMagicNumberEMACross))
ClosePosition(symbol, RM_InpMagicNumberEMACross);
}
return;
}
if(RM_InpEnableStrategyLock && HasProfitablePosition(RM_InpMagicNumberEMACross))
return;
if(rmData.lastBarEMAPrev < rmData.lastBarClosePrev && rmData.lastBarEMA > rmData.lastBarClose)
{
rmData.emaCrossBuySignal = true;
rmData.emaCrossSellSignal = false;
rmData.emaCrossSignalBar = 0;
}
else if(rmData.lastBarEMAPrev > rmData.lastBarClosePrev && rmData.lastBarEMA < rmData.lastBarClose)
{
rmData.emaCrossSellSignal = true;
rmData.emaCrossBuySignal = false;
rmData.emaCrossSignalBar = 0;
}
if(RM_InpUseEMADistanceEntry)
{
if(rmData.emaCrossBuySignal)
{
bool distanceConditionMet = true;
double emaHistory[], closeHistory[];
ArraySetAsSeries(emaHistory, true);
ArraySetAsSeries(closeHistory, true);
if(CopyBuffer(rmData.emaHandle, 0, 0, RM_InpEMADistancePeriod, emaHistory) > 0 &&
CopyClose(symbol, RM_InpTimeframe, 0, RM_InpEMADistancePeriod, closeHistory) > 0)
{
double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
for(int i = 0; i < RM_InpEMADistancePeriod; i++)
{
double distance = (closeHistory[i] - emaHistory[i]) / point;
if(distance < RM_InpEMADistancePips)
{
distanceConditionMet = false;
break;
}
}
if(distanceConditionMet && !HasPosition(symbol, RM_InpMagicNumberEMACross))
{
rmData.trade.SetExpertMagicNumber(RM_InpMagicNumberEMACross);
const double vol = RM_NormalizedLot(symbol);
if(vol > 0.0)
rmData.trade.Buy(vol, symbol, 0, 0, 0, "EMA Cross Distance");
rmData.emaCrossBuySignal = false;
}
}
}
else if(rmData.emaCrossSellSignal)
{
bool distanceConditionMet = true;
double emaHistory[], closeHistory[];
ArraySetAsSeries(emaHistory, true);
ArraySetAsSeries(closeHistory, true);
if(CopyBuffer(rmData.emaHandle, 0, 0, RM_InpEMADistancePeriod, emaHistory) > 0 &&
CopyClose(symbol, RM_InpTimeframe, 0, RM_InpEMADistancePeriod, closeHistory) > 0)
{
double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
for(int i = 0; i < RM_InpEMADistancePeriod; i++)
{
double distance = (emaHistory[i] - closeHistory[i]) / point;
if(distance < RM_InpEMADistancePips)
{
distanceConditionMet = false;
break;
}
}
if(distanceConditionMet && !HasPosition(symbol, RM_InpMagicNumberEMACross))
{
rmData.trade.SetExpertMagicNumber(RM_InpMagicNumberEMACross);
const double vol = RM_NormalizedLot(symbol);
if(vol > 0.0)
rmData.trade.Sell(vol, symbol, 0, 0, 0, "EMA Cross Distance");
rmData.emaCrossSellSignal = false;
}
}
}
}
else
{
if(rmData.lastBarEMAPrev < rmData.lastBarClosePrev && rmData.lastBarEMA > rmData.lastBarClose)
{
if(!HasPosition(symbol, RM_InpMagicNumberEMACross))
{
rmData.trade.SetExpertMagicNumber(RM_InpMagicNumberEMACross);
const double vol = RM_NormalizedLot(symbol);
if(vol > 0.0)
rmData.trade.Buy(vol, symbol, 0, 0, 0, "EMA Cross");
}
}
else if(rmData.lastBarEMAPrev > rmData.lastBarClosePrev && rmData.lastBarEMA < rmData.lastBarClose)
{
if(!HasPosition(symbol, RM_InpMagicNumberEMACross))
{
rmData.trade.SetExpertMagicNumber(RM_InpMagicNumberEMACross);
const double vol = RM_NormalizedLot(symbol);
if(vol > 0.0)
rmData.trade.Sell(vol, symbol, 0, 0, 0, "EMA Cross");
}
}
}
if(rmData.emaCrossBuySignal || rmData.emaCrossSellSignal)
{
rmData.emaCrossSignalBar++;
if(rmData.emaCrossSignalBar > RM_InpEMADistancePeriod * 2)
{
rmData.emaCrossBuySignal = false;
rmData.emaCrossSellSignal = false;
}
}
}
void CheckExitConditions(string symbol)
{
if(RM_InpEnableRSIFollow)
{
if(HasPosition(symbol, RM_InpMagicNumberRSIFollow))
{
if(PositionSelectByMagic(symbol, RM_InpMagicNumberRSIFollow))
{
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if((posType == POSITION_TYPE_BUY && rmData.lastBarRSI < RM_InpRSIExitLevel) ||
(posType == POSITION_TYPE_SELL && rmData.lastBarRSI > RM_InpRSIExitLevel))
{
ClosePosition(symbol, RM_InpMagicNumberRSIFollow);
}
}
}
}
if(RM_InpEnableRSIReverse)
{
if(HasPosition(symbol, RM_InpMagicNumberRSIReverse))
{
if(PositionSelectByMagic(symbol, RM_InpMagicNumberRSIReverse))
{
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if((posType == POSITION_TYPE_BUY && rmData.lastBarRSIReverse < RM_InpRSIReverseExitLevel) ||
(posType == POSITION_TYPE_SELL && rmData.lastBarRSIReverse > RM_InpRSIReverseExitLevel))
{
ClosePosition(symbol, RM_InpMagicNumberRSIReverse);
}
}
}
}
if(RM_InpEnableEMACross)
{
if(HasPosition(symbol, RM_InpMagicNumberEMACross))
{
if(PositionSelectByMagic(symbol, RM_InpMagicNumberEMACross))
{
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if((posType == POSITION_TYPE_BUY && rmData.lastBarEMA > rmData.lastBarClose) ||
(posType == POSITION_TYPE_SELL && rmData.lastBarEMA < rmData.lastBarClose))
{
ClosePosition(symbol, RM_InpMagicNumberEMACross);
}
}
}
}
}
void ClosePosition(string symbol, int magic)
{
if(!PositionExistsByMagic(symbol, magic))
return;
ulong ticket = GetPositionTicketByMagic(symbol, magic);
if(ticket == 0)
return;
if(magic == RM_InpMagicNumberRSIReverse)
{
if(PositionSelectByTicketSymbolAndMagic(ticket, symbol, magic))
{
datetime time[];
if(CopyTime(symbol, RM_InpTimeframe, 0, 1, time) > 0)
{
rmData.rsiReverseLastCloseTime = time[0];
double profit = PositionGetDouble(POSITION_PROFIT);
if(!RM_InpRSIReverseCooldownOnLoss || profit < 0)
{
rmData.rsiReverseInCooldown = true;
}
}
}
}
ClosePositionByMagic(rmData.trade, symbol, magic);
}
bool InitRSIMidPointHijack(string symbol)
{
rmData.symbol = symbol;
rmData.rsiOverbought = false;
rmData.rsiOversold = false;
rmData.rsiReverseOverbought = false;
rmData.rsiReverseOversold = false;
rmData.emaCrossBuySignal = false;
rmData.emaCrossSellSignal = false;
rmData.emaCrossSignalBar = 0;
rmData.rsiReverseInCooldown = false;
rmData.lastBarRSI = 0;
rmData.lastBarRSIReverse = 0;
rmData.lastBarEMA = 0;
rmData.lastBarClose = 0;
rmData.lastBarEMAPrev = 0;
rmData.lastBarClosePrev = 0;
// Check if symbol exists
if(!SymbolSelect(symbol, true))
{
Print("RSIMidPointHijack: Symbol '", symbol, "' not available in Market Watch. Please add it to Market Watch or check symbol name.");
return false;
}
Sleep(100); // Wait for symbol to be ready
rmData.rsiHandle = iRSI(symbol, RM_InpTimeframe, RM_InpRSIPeriod, PRICE_CLOSE);
rmData.rsiReverseHandle = iRSI(symbol, RM_InpTimeframe, RM_InpRSIReversePeriod, PRICE_CLOSE);
rmData.emaHandle = iMA(symbol, RM_InpTimeframe, RM_InpEMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
if(rmData.rsiHandle == INVALID_HANDLE || rmData.rsiReverseHandle == INVALID_HANDLE || rmData.emaHandle == INVALID_HANDLE)
{
Print("RSIMidPointHijack: Error creating indicators for '", symbol, "'");
return false;
}
rmData.trade.SetExpertMagicNumber(RM_InpMagicNumberRSIFollow);
rmData.trade.SetMarginMode();
rmData.trade.SetTypeFillingBySymbol(symbol);
rmData.trade.SetDeviationInPoints(10);
datetime time[];
if(CopyTime(symbol, RM_InpTimeframe, 0, 1, time) > 0)
rmData.lastBarTime = time[0];
rmData.isInitialized = true;
Print("RSIMidPointHijack: Successfully initialized for symbol '", symbol, "'");
return true;
}
void DeinitRSIMidPointHijack()
{
if(rmData.rsiHandle != INVALID_HANDLE) IndicatorRelease(rmData.rsiHandle);
if(rmData.rsiReverseHandle != INVALID_HANDLE) IndicatorRelease(rmData.rsiReverseHandle);
if(rmData.emaHandle != INVALID_HANDLE) IndicatorRelease(rmData.emaHandle);
}
void ProcessRSIMidPointHijack(string symbol)
{
// Skip if not initialized (symbol not available)
if(!rmData.isInitialized)
return;
rmData.symbol = symbol; // Update symbol in case it changed
if(!IsNewBar(rmData.symbol))
return;
double rsi[], rsiReverse[], ema[], close[];
ArraySetAsSeries(rsi, true);
ArraySetAsSeries(rsiReverse, true);
ArraySetAsSeries(ema, true);
ArraySetAsSeries(close, true);
rmData.lastBarEMAPrev = rmData.lastBarEMA;
rmData.lastBarClosePrev = rmData.lastBarClose;
if(CopyBuffer(rmData.rsiHandle, 0, 0, 1, rsi) > 0)
rmData.lastBarRSI = rsi[0];
if(CopyBuffer(rmData.rsiReverseHandle, 0, 0, 1, rsiReverse) > 0)
rmData.lastBarRSIReverse = rsiReverse[0];
if(CopyBuffer(rmData.emaHandle, 0, 0, 1, ema) > 0)
rmData.lastBarEMA = ema[0];
if(CopyClose(rmData.symbol, RM_InpTimeframe, 0, 1, close) > 0)
rmData.lastBarClose = close[0];
if(RM_InpEnableRSIFollow)
CheckRSIFollowStrategy(rmData.symbol);
if(RM_InpEnableRSIReverse)
CheckRSIReverseStrategy(rmData.symbol);
if(RM_InpEnableEMACross)
CheckEMACrossStrategy(rmData.symbol);
CheckExitConditions(rmData.symbol);
}
//+------------------------------------------------------------------+
@@ -1,488 +0,0 @@
//+------------------------------------------------------------------+
//| RSIReversalAsianStrategy.mqh |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| RSI Reversal Asian Strategy Data Structure |
//+------------------------------------------------------------------+
struct RSIReversalAsianData {
string symbol;
bool isInitialized;
int rsiHandle;
CTrade trade;
bool isPositionOpen;
double positionOpenPrice;
datetime positionOpenTime;
ENUM_POSITION_TYPE lastPositionType;
bool sessionCloseAttempted;
// RSI crossover variables
double rsiCurrent;
double rsiPrevious;
double rsiPrevious2;
bool rsiCrossedOverbought;
bool rsiCrossedOversold;
bool rsiCrossedExitLevel;
// Strategy parameters
int RSIPeriod;
double OverboughtLevel;
double OversoldLevel;
int TakeProfitPips;
int StopLossPips;
double MaxLotSize;
int MaxSpread;
int MaxDuration;
bool UseStopLoss;
bool UseTakeProfit;
bool UseRSIExit;
double RSIExitLevel;
bool CloseOutsideSession;
ENUM_TIMEFRAMES TimeFrame;
int MagicNumber;
int Slippage;
double point;
};
// Session times (UTC)
const int AsianSessionStart = 0; // 00:00 UTC
const int AsianSessionEnd = 8; // 08:00 UTC
//+------------------------------------------------------------------+
//| Check if current time is in Asian session |
//+------------------------------------------------------------------+
bool IsAsianSession()
{
datetime currentTime = TimeCurrent();
MqlDateTime timeStruct;
TimeToStruct(currentTime, timeStruct);
return (timeStruct.hour >= AsianSessionStart && timeStruct.hour < AsianSessionEnd);
}
//+------------------------------------------------------------------+
//| Check if trading is allowed for symbol |
//+------------------------------------------------------------------+
bool IsTradingAllowed(RSIReversalAsianData& data)
{
// Do not require SYMBOL_TRADE_MODE_FULL: many symbols allow one side only (long/short).
const long tradeMode = SymbolInfoInteger(data.symbol, SYMBOL_TRADE_MODE);
if(tradeMode == SYMBOL_TRADE_MODE_DISABLED || tradeMode == SYMBOL_TRADE_MODE_CLOSEONLY)
return false;
if(AccountInfoDouble(ACCOUNT_MARGIN_FREE) <= 0)
return false;
return true;
}
//+------------------------------------------------------------------+
//| Check RSI crossover conditions |
//+------------------------------------------------------------------+
void CheckRSICrossover(RSIReversalAsianData& data)
{
// Reset crossover flags
data.rsiCrossedOverbought = false;
data.rsiCrossedOversold = false;
data.rsiCrossedExitLevel = false;
// Check for overbought crossover (RSI crosses above overbought level)
if(data.rsiPrevious < data.OverboughtLevel && data.rsiCurrent >= data.OverboughtLevel)
{
data.rsiCrossedOverbought = true;
}
// Check for oversold crossover (RSI crosses below oversold level)
if(data.rsiPrevious > data.OversoldLevel && data.rsiCurrent <= data.OversoldLevel)
{
data.rsiCrossedOversold = true;
}
// Check for exit level crossover
if(data.rsiPrevious < data.RSIExitLevel && data.rsiCurrent >= data.RSIExitLevel)
{
data.rsiCrossedExitLevel = true;
}
else if(data.rsiPrevious > data.RSIExitLevel && data.rsiCurrent <= data.RSIExitLevel)
{
data.rsiCrossedExitLevel = true;
}
}
//+------------------------------------------------------------------+
//| Close all trades for the symbol |
//+------------------------------------------------------------------+
bool CloseAllTrades(RSIReversalAsianData& data, string reason = "")
{
bool allClosed = true;
int totalPositions = PositionsTotal();
if(totalPositions == 0)
return true;
for(int i = totalPositions - 1; i >= 0; i--)
{
if(PositionGetSymbol(i) == data.symbol)
{
ulong ticket = PositionGetTicket(i);
if(ticket > 0 && PositionSelectByTicket(ticket))
{
if(PositionGetInteger(POSITION_MAGIC) == (ulong)data.MagicNumber)
{
// Try to close position with retry logic
int retryCount = 0;
bool positionClosed = false;
while(retryCount < 3 && !positionClosed)
{
if(data.trade.PositionClose(ticket))
{
data.isPositionOpen = false;
positionClosed = true;
}
else
{
int error = GetLastError();
// If error is 4756 (Trade disabled), wait longer before retry
if(error == 4756)
{
Sleep(5000); // Wait 5 seconds before retry
retryCount++;
}
else
{
// For other errors, break the loop
break;
}
}
}
if(!positionClosed)
{
allClosed = false;
}
}
}
}
}
return allClosed;
}
//+------------------------------------------------------------------+
//| Initialize RSI Reversal Asian Strategy |
//+------------------------------------------------------------------+
bool InitRSIReversalAsian(RSIReversalAsianData& data, string symbol,
int RSIPeriod, double OverboughtLevel, double OversoldLevel,
int TakeProfitPips, int StopLossPips, double MaxLotSize,
int MaxSpread, int MaxDuration, bool UseStopLoss,
bool UseTakeProfit, bool UseRSIExit, double RSIExitLevel,
bool CloseOutsideSession, ENUM_TIMEFRAMES TimeFrame,
int MagicNumber, int Slippage)
{
data.symbol = symbol;
data.isInitialized = false;
// Check if symbol exists
if(!SymbolSelect(symbol, true))
{
Print("RSIReversalAsian: Symbol '", symbol, "' not available in Market Watch. Please add it to Market Watch or check symbol name.");
return false;
}
// Wait a bit for symbol to be ready
Sleep(100);
// Get symbol point
data.point = SymbolInfoDouble(symbol, SYMBOL_POINT);
// Store parameters
data.RSIPeriod = RSIPeriod;
data.OverboughtLevel = OverboughtLevel;
data.OversoldLevel = OversoldLevel;
data.TakeProfitPips = TakeProfitPips;
data.StopLossPips = StopLossPips;
data.MaxLotSize = MaxLotSize;
data.MaxSpread = MaxSpread;
data.MaxDuration = MaxDuration;
data.UseStopLoss = UseStopLoss;
data.UseTakeProfit = UseTakeProfit;
data.UseRSIExit = UseRSIExit;
data.RSIExitLevel = RSIExitLevel;
data.CloseOutsideSession = CloseOutsideSession;
data.TimeFrame = TimeFrame;
data.MagicNumber = MagicNumber;
data.Slippage = Slippage;
// Initialize RSI indicator with retry logic (for insufficient history in backtesting)
data.rsiHandle = INVALID_HANDLE;
int retryCount = 0;
int maxRetries = 5;
while(retryCount < maxRetries && data.rsiHandle == INVALID_HANDLE)
{
data.rsiHandle = iRSI(symbol, TimeFrame, RSIPeriod, PRICE_CLOSE);
if(data.rsiHandle == INVALID_HANDLE)
{
int error = GetLastError();
// Error 4805 = insufficient history - wait longer and retry
if(error == 4805 && retryCount < maxRetries - 1)
{
Sleep(1000); // Wait 1 second for history to load
retryCount++;
continue;
}
Print("RSIReversalAsian: Error creating RSI indicator for '", symbol, "' - Error: ", error, " (", error == 4805 ? "Insufficient history data" : "Unknown", ")");
return false;
}
}
if(data.rsiHandle == INVALID_HANDLE)
{
Print("RSIReversalAsian: Failed to create RSI indicator for '", symbol, "' after ", maxRetries, " retries");
return false;
}
// Wait a bit for the indicator to be ready
Sleep(100);
// Initialize RSI values with retry logic
double rsi[];
ArraySetAsSeries(rsi, true);
retryCount = 0;
bool rsiInitialized = false;
while(retryCount < 10 && !rsiInitialized)
{
int copied = CopyBuffer(data.rsiHandle, 0, 0, 3, rsi);
if(copied >= 3)
{
data.rsiCurrent = rsi[0];
data.rsiPrevious = rsi[1];
data.rsiPrevious2 = rsi[2];
rsiInitialized = true;
}
else
{
retryCount++;
Sleep(100);
}
}
if(!rsiInitialized)
{
// Don't fail initialization, just set default values
data.rsiCurrent = 50.0;
data.rsiPrevious = 50.0;
data.rsiPrevious2 = 50.0;
}
// Set trade parameters
data.trade.SetExpertMagicNumber(MagicNumber);
data.trade.SetDeviationInPoints(Slippage);
data.trade.SetTypeFillingBySymbol(symbol);
// Initialize state
data.isPositionOpen = false;
data.positionOpenPrice = 0;
data.positionOpenTime = 0;
data.lastPositionType = POSITION_TYPE_BUY;
data.sessionCloseAttempted = false;
data.rsiCrossedOverbought = false;
data.rsiCrossedOversold = false;
data.rsiCrossedExitLevel = false;
data.isInitialized = true;
Print("RSIReversalAsian: Successfully initialized for symbol '", symbol, "'");
return true;
}
//+------------------------------------------------------------------+
//| Deinitialize RSI Reversal Asian Strategy |
//+------------------------------------------------------------------+
void DeinitRSIReversalAsian(RSIReversalAsianData& data)
{
if(data.rsiHandle != INVALID_HANDLE)
IndicatorRelease(data.rsiHandle);
}
//+------------------------------------------------------------------+
//| Process RSI Reversal Asian Strategy |
//+------------------------------------------------------------------+
void ProcessRSIReversalAsian(RSIReversalAsianData& data, double lotSize)
{
if(!data.isInitialized)
return;
// Check if trading is allowed
if(!IsTradingAllowed(data))
{
return;
}
// Check if we're in Asian session
if(!IsAsianSession())
{
// Close all positions if outside Asian session and CloseOutsideSession is true
if(data.CloseOutsideSession && !data.sessionCloseAttempted)
{
CloseAllTrades(data, "Outside Asian session");
data.sessionCloseAttempted = true;
}
return;
}
else
{
// Reset the session close attempt flag when we enter Asian session
data.sessionCloseAttempted = false;
}
// Get current spread
double spread = SymbolInfoDouble(data.symbol, SYMBOL_ASK) - SymbolInfoDouble(data.symbol, SYMBOL_BID);
int spreadInPips = (int)(spread / data.point);
// Check if spread is too high
if(spreadInPips > data.MaxSpread)
{
return;
}
// Get RSI values from bar data
double rsi[];
ArraySetAsSeries(rsi, true);
int copied = CopyBuffer(data.rsiHandle, 0, 0, 3, rsi);
if(copied < 3)
{
return;
}
// Update RSI values
data.rsiPrevious2 = data.rsiPrevious;
data.rsiPrevious = data.rsiCurrent;
data.rsiCurrent = rsi[0];
// Validate RSI values
if(data.rsiCurrent == 0 || data.rsiPrevious == 0)
{
return;
}
// Check for RSI crossovers
CheckRSICrossover(data);
// Get current prices
double currentBid = SymbolInfoDouble(data.symbol, SYMBOL_BID);
double currentAsk = SymbolInfoDouble(data.symbol, SYMBOL_ASK);
// Check for open position
bool hasOpenPosition = PositionExistsByMagic(data.symbol, (ulong)data.MagicNumber);
if(hasOpenPosition)
{
// Get position details
ulong ticket = GetPositionTicketByMagic(data.symbol, (ulong)data.MagicNumber);
if(ticket > 0 && PositionSelectByTicket(ticket))
{
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
datetime openTime = (datetime)PositionGetInteger(POSITION_TIME);
// Check for RSI exit if enabled
if(data.UseRSIExit && data.rsiCrossedExitLevel)
{
bool shouldExit = false;
// For long positions, exit when RSI crosses above exit level
if(posType == POSITION_TYPE_BUY && data.rsiCurrent >= data.RSIExitLevel && data.rsiPrevious < data.RSIExitLevel)
{
shouldExit = true;
}
// For short positions, exit when RSI crosses below exit level
else if(posType == POSITION_TYPE_SELL && data.rsiCurrent <= data.RSIExitLevel && data.rsiPrevious > data.RSIExitLevel)
{
shouldExit = true;
}
if(shouldExit)
{
CloseAllTrades(data, "RSI Exit Crossover");
return;
}
}
// Check for timeout
if(TimeCurrent() - openTime > data.MaxDuration * 3600)
{
CloseAllTrades(data, "Timeout");
return;
}
}
}
// If no position is open, look for entry signals based on RSI crossover
if(!hasOpenPosition)
{
// Place buy order if RSI crosses below oversold level (oversold crossover)
if(data.rsiCrossedOversold)
{
double sl = data.UseStopLoss ? currentBid - data.StopLossPips * data.point : 0;
double tp = data.UseTakeProfit ? currentBid + data.TakeProfitPips * data.point : 0;
if(data.UseStopLoss && sl >= currentBid)
return;
if(data.UseTakeProfit && tp <= currentBid)
return;
data.trade.SetDeviationInPoints(data.Slippage);
data.trade.SetTypeFillingBySymbol(data.symbol);
data.trade.SetExpertMagicNumber(data.MagicNumber);
double tradeLotSize = lotSize > 0 ? lotSize : data.MaxLotSize;
const double vol = United_NormalizeVolume(data.symbol, tradeLotSize);
if(vol <= 0.0)
return;
if(data.trade.Buy(vol, data.symbol, currentAsk, sl, tp, "RSI Oversold Crossover Buy"))
{
data.isPositionOpen = true;
data.positionOpenPrice = currentAsk;
data.positionOpenTime = TimeCurrent();
data.lastPositionType = POSITION_TYPE_BUY;
}
}
// Place sell order if RSI crosses above overbought level (overbought crossover)
else if(data.rsiCrossedOverbought)
{
double sl = data.UseStopLoss ? currentAsk + data.StopLossPips * data.point : 0;
double tp = data.UseTakeProfit ? currentAsk - data.TakeProfitPips * data.point : 0;
if(data.UseStopLoss && sl <= currentAsk)
return;
if(data.UseTakeProfit && tp >= currentAsk)
return;
data.trade.SetDeviationInPoints(data.Slippage);
data.trade.SetTypeFillingBySymbol(data.symbol);
data.trade.SetExpertMagicNumber(data.MagicNumber);
double tradeLotSize = lotSize > 0 ? lotSize : data.MaxLotSize;
const double vol = United_NormalizeVolume(data.symbol, tradeLotSize);
if(vol <= 0.0)
return;
if(data.trade.Sell(vol, data.symbol, currentBid, sl, tp, "RSI Overbought Crossover Sell"))
{
data.isPositionOpen = true;
data.positionOpenPrice = currentBid;
data.positionOpenTime = TimeCurrent();
data.lastPositionType = POSITION_TYPE_SELL;
}
}
}
}
@@ -1,615 +0,0 @@
//+------------------------------------------------------------------+
//| RSIScalpingStrategy.mqh |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| RSI Scalping Strategy Data Structure |
//+------------------------------------------------------------------+
struct RSIScalpingData {
string symbol;
bool isInitialized;
CTrade trade;
int rsi_handle;
double rsi_buffer[];
double rsi_prev;
double rsi_current;
double rsi_two_bars_ago;
bool position_open;
ulong position_ticket;
ENUM_POSITION_TYPE current_position_type;
datetime last_bar_time;
bool rsi_against_position;
int bars_against_count;
};
void ClosePosition(RSIScalpingData& data, int MagicNumber);
double RS_ATRPriceOnTF(const string symbol, const ENUM_TIMEFRAMES tf, const int period)
{
if(period < 1)
return 0.0;
MqlRates rates[];
const int need = period + 2;
if(CopyRates(symbol, tf, 0, need, rates) < need)
return 0.0;
ArraySetAsSeries(rates, true);
double sum = 0.0;
for(int i = 1; i <= period; i++)
{
const double hl = rates[i].high - rates[i].low;
const double hc = MathAbs(rates[i].high - rates[i + 1].close);
const double lc = MathAbs(rates[i].low - rates[i + 1].close);
sum += MathMax(hl, MathMax(hc, lc));
}
return sum / (double)period;
}
int RS_CountReversalEscapeSigns(RSIScalpingData& data, const ENUM_TIMEFRAMES tf,
const ENUM_POSITION_TYPE ptype, const double atr,
const double adverseAtrMult, const double rsiVelocity,
const double bodyAtrMult)
{
if(atr <= 0.0)
return 0;
const double entry = PositionGetDouble(POSITION_PRICE_OPEN);
const double bid = SymbolInfoDouble(data.symbol, SYMBOL_BID);
const double ask = SymbolInfoDouble(data.symbol, SYMBOL_ASK);
int signs = 0;
if(ptype == POSITION_TYPE_BUY)
{
if(entry - bid >= adverseAtrMult * atr)
signs++;
if(data.rsi_prev - data.rsi_current >= rsiVelocity)
signs++;
}
else if(ptype == POSITION_TYPE_SELL)
{
if(ask - entry >= adverseAtrMult * atr)
signs++;
if(data.rsi_current - data.rsi_prev >= rsiVelocity)
signs++;
}
else
return 0;
MqlRates r[];
if(CopyRates(data.symbol, tf, 0, 4, r) >= 4)
{
ArraySetAsSeries(r, true);
const double body = MathAbs(r[1].close - r[1].open);
if(body >= bodyAtrMult * atr)
{
if(ptype == POSITION_TYPE_BUY && r[1].close < r[1].open)
signs++;
else if(ptype == POSITION_TYPE_SELL && r[1].close > r[1].open)
signs++;
}
if(ptype == POSITION_TYPE_BUY)
{
if(r[1].close < r[2].close && r[2].close < r[3].close)
signs++;
}
else
{
if(r[1].close > r[2].close && r[2].close > r[3].close)
signs++;
}
}
return signs;
}
void RS_TryReversalEscape(RSIScalpingData& data, const ENUM_TIMEFRAMES tf, const int MagicNumber,
const int atrPeriod, const double adverseAtrMult, const int signsRequired,
const double rsiVelocity, const double bodyAtrMult)
{
if(!PositionSelectByMagic(data.symbol, (ulong)MagicNumber))
return;
const ENUM_POSITION_TYPE ptype = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
const double atr = RS_ATRPriceOnTF(data.symbol, tf, atrPeriod);
if(atr <= 0.0)
return;
const int n = RS_CountReversalEscapeSigns(data, tf, ptype, atr, adverseAtrMult, rsiVelocity, bodyAtrMult);
if(n < signsRequired)
return;
ClosePosition(data, MagicNumber);
Print("RSIScalping: reversal escape symbol=", data.symbol, " signs=", n, " need=", signsRequired,
" ATR=", DoubleToString(atr, (int)SymbolInfoInteger(data.symbol, SYMBOL_DIGITS)));
}
void RS_ApplyTrailingStop(RSIScalpingData& data, const int MagicNumber,
const bool useTrailingStop,
const double trailingStopDistancePoints,
const double trailingActivationPoints)
{
if(!useTrailingStop || trailingStopDistancePoints <= 0.0)
return;
if(!PositionSelectByMagic(data.symbol, (ulong)MagicNumber))
return;
const double point = SymbolInfoDouble(data.symbol, SYMBOL_POINT);
if(point <= 0.0)
return;
const int digits = (int)SymbolInfoInteger(data.symbol, SYMBOL_DIGITS);
const double trail_dist = trailingStopDistancePoints * point;
const double activation_pts = (trailingActivationPoints > 0.0)
? trailingActivationPoints
: trailingStopDistancePoints;
const double activation = activation_pts * point;
const long stops_level = SymbolInfoInteger(data.symbol, SYMBOL_TRADE_STOPS_LEVEL);
const double min_dist = (double)stops_level * point;
const ENUM_POSITION_TYPE ptype = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
const double entry = PositionGetDouble(POSITION_PRICE_OPEN);
const double cur_sl = PositionGetDouble(POSITION_SL);
const double cur_tp = PositionGetDouble(POSITION_TP);
if(ptype == POSITION_TYPE_BUY)
{
const double bid = SymbolInfoDouble(data.symbol, SYMBOL_BID);
if(bid - entry <= activation)
return;
double new_sl = NormalizeDouble(bid - trail_dist, digits);
if(min_dist > 0.0 && bid - new_sl < min_dist)
new_sl = NormalizeDouble(bid - min_dist, digits);
if(new_sl >= bid || new_sl <= 0.0)
return;
if(cur_sl > 0.0 && new_sl <= cur_sl)
return;
ModifyPositionByMagic(data.trade, data.symbol, (ulong)MagicNumber, new_sl, cur_tp);
}
else if(ptype == POSITION_TYPE_SELL)
{
const double ask = SymbolInfoDouble(data.symbol, SYMBOL_ASK);
if(entry - ask <= activation)
return;
double new_sl = NormalizeDouble(ask + trail_dist, digits);
if(min_dist > 0.0 && new_sl - ask < min_dist)
new_sl = NormalizeDouble(ask + min_dist, digits);
if(new_sl <= ask || new_sl <= 0.0)
return;
if(cur_sl > 0.0 && new_sl >= cur_sl)
return;
ModifyPositionByMagic(data.trade, data.symbol, (ulong)MagicNumber, new_sl, cur_tp);
}
}
string ErrorDescription(int errorCode)
{
switch(errorCode)
{
case 4801: return "Symbol not found";
case 4802: return "Symbol not selected";
case 4803: return "Symbol not visible";
case 4804: return "Symbol not available";
case 4805: return "Cannot load indicator - insufficient history data";
default: return "Unknown error " + IntegerToString(errorCode);
}
}
bool InitRSIScalping(RSIScalpingData& data, string symbol, ENUM_TIMEFRAMES TimeFrame, int RSI_Period,
ENUM_APPLIED_PRICE RSI_Applied_Price, int MagicNumber, int Slippage)
{
data.symbol = symbol;
data.isInitialized = false;
// Check if symbol exists
if(!SymbolSelect(symbol, true))
{
Print("RSIScalping: Symbol '", symbol, "' not available in Market Watch. Please add it to Market Watch or check symbol name.");
return false; // Return false but don't fail entire EA
}
// Wait a bit for symbol to be ready
Sleep(100);
// Try to create RSI indicator with retry logic (for insufficient history in backtesting)
data.rsi_handle = INVALID_HANDLE;
int retryCount = 0;
int maxRetries = 5;
while(retryCount < maxRetries && data.rsi_handle == INVALID_HANDLE)
{
data.rsi_handle = iRSI(symbol, TimeFrame, RSI_Period, RSI_Applied_Price);
if(data.rsi_handle == INVALID_HANDLE)
{
int error = GetLastError();
// Error 4805 = insufficient history - wait longer and retry
if(error == 4805 && retryCount < maxRetries - 1)
{
Sleep(1000); // Wait 1 second for history to load
retryCount++;
continue;
}
Print("RSIScalping: Error creating RSI indicator for '", symbol, "' - Error: ", error, " (", ErrorDescription(error), ")");
return false; // Return false but don't fail entire EA
}
}
if(data.rsi_handle == INVALID_HANDLE)
{
Print("RSIScalping: Failed to create RSI indicator for '", symbol, "' after ", maxRetries, " retries");
return false;
}
data.trade.SetExpertMagicNumber(MagicNumber);
data.trade.SetDeviationInPoints(Slippage);
data.trade.SetTypeFilling(ORDER_FILLING_FOK);
ArraySetAsSeries(data.rsi_buffer, true);
data.position_open = false;
data.position_ticket = 0;
data.rsi_against_position = false;
data.bars_against_count = 0;
data.isInitialized = true;
Print("RSIScalping: Successfully initialized for symbol '", symbol, "'");
return true;
}
void DeinitRSIScalping(RSIScalpingData& data)
{
if(data.rsi_handle != INVALID_HANDLE)
IndicatorRelease(data.rsi_handle);
}
bool UpdateRSI(RSIScalpingData& data)
{
if(CopyBuffer(data.rsi_handle, 0, 0, 3, data.rsi_buffer) < 3)
return false;
data.rsi_current = data.rsi_buffer[0];
data.rsi_prev = data.rsi_buffer[1];
data.rsi_two_bars_ago = data.rsi_buffer[2];
return true;
}
void CheckExistingPosition(RSIScalpingData& data, ENUM_TIMEFRAMES TimeFrame, int MagicNumber,
double RSI_Oversold, double RSI_Overbought, double RSI_Target_Buy,
double RSI_Target_Sell, int BarsToWait)
{
// Always check if position exists, even if tracking says it doesn't
bool positionExists = PositionExistsByMagic(data.symbol, MagicNumber);
if(!positionExists && data.position_open)
{
// Position was closed externally, reset tracking
data.position_open = false;
data.position_ticket = 0;
data.rsi_against_position = false;
data.bars_against_count = 0;
return;
}
if(!positionExists)
return;
// Update tracking if we have a position but tracking was lost
if(!data.position_open && positionExists)
{
ulong ticket = GetPositionTicketByMagic(data.symbol, MagicNumber);
if(ticket > 0 && PositionSelectByTicketSymbolAndMagic(ticket, data.symbol, MagicNumber))
{
data.position_ticket = ticket;
data.position_open = true;
data.current_position_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
}
}
// Verify our tracked position still exists
if(data.position_open && data.position_ticket > 0)
{
if(!PositionSelectByTicketSymbolAndMagic(data.position_ticket, data.symbol, MagicNumber))
{
// Try to find the position again
ulong ticket = GetPositionTicketByMagic(data.symbol, MagicNumber);
if(ticket > 0 && PositionSelectByTicketSymbolAndMagic(ticket, data.symbol, MagicNumber))
{
data.position_ticket = ticket;
data.current_position_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
}
else
{
// Position doesn't exist, reset tracking
data.position_open = false;
data.position_ticket = 0;
data.rsi_against_position = false;
data.bars_against_count = 0;
return;
}
}
else
{
// Update position type in case it changed (shouldn't happen, but be safe)
data.current_position_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
}
}
if(data.current_position_type == POSITION_TYPE_BUY)
{
if(data.rsi_current < RSI_Oversold)
{
if(!data.rsi_against_position)
{
data.rsi_against_position = true;
data.bars_against_count = 1;
}
else
{
data.bars_against_count++;
}
if(data.bars_against_count >= BarsToWait)
{
ClosePosition(data, MagicNumber);
return;
}
}
else
{
if(data.rsi_against_position)
{
data.rsi_against_position = false;
data.bars_against_count = 0;
}
if(data.rsi_current >= RSI_Target_Buy)
{
ClosePosition(data, MagicNumber);
}
}
}
else if(data.current_position_type == POSITION_TYPE_SELL)
{
if(data.rsi_current > RSI_Overbought)
{
if(!data.rsi_against_position)
{
data.rsi_against_position = true;
data.bars_against_count = 1;
}
else
{
data.bars_against_count++;
}
if(data.bars_against_count >= BarsToWait)
{
ClosePosition(data, MagicNumber);
return;
}
}
else
{
if(data.rsi_against_position)
{
data.rsi_against_position = false;
data.bars_against_count = 0;
}
if(data.rsi_current <= RSI_Target_Sell)
{
ClosePosition(data, MagicNumber);
}
}
}
}
void CheckEntrySignals(RSIScalpingData& data, ENUM_TIMEFRAMES TimeFrame, int MagicNumber,
double RSI_Oversold, double RSI_Overbought, double LotSize)
{
if(data.rsi_two_bars_ago <= RSI_Oversold && data.rsi_prev > RSI_Oversold)
{
OpenBuyPosition(data, MagicNumber, LotSize);
}
if(data.rsi_two_bars_ago >= RSI_Overbought && data.rsi_prev < RSI_Overbought)
{
OpenSellPosition(data, MagicNumber, LotSize);
}
}
//+------------------------------------------------------------------+
//| Normalize Lot Size According to Symbol Properties |
//+------------------------------------------------------------------+
double NormalizeLotSize(string symbol, double lotSize)
{
return United_NormalizeVolume(symbol, lotSize);
}
void OpenBuyPosition(RSIScalpingData& data, int MagicNumber, double LotSize)
{
if(PositionExistsByMagic(data.symbol, MagicNumber))
return;
// Normalize lot size according to symbol properties
double normalizedLot = NormalizeLotSize(data.symbol, LotSize);
double ask = SymbolInfoDouble(data.symbol, SYMBOL_ASK);
if(data.trade.Buy(normalizedLot, data.symbol, ask, 0, 0, "RSI Scalping Buy"))
{
ulong new_ticket = data.trade.ResultOrder();
if(new_ticket > 0)
{
if(PositionSelectByTicketSymbolAndMagic(new_ticket, data.symbol, MagicNumber))
{
data.position_ticket = new_ticket;
data.position_open = true;
data.current_position_type = POSITION_TYPE_BUY;
}
}
}
}
void OpenSellPosition(RSIScalpingData& data, int MagicNumber, double LotSize)
{
if(PositionExistsByMagic(data.symbol, MagicNumber))
return;
// Normalize lot size according to symbol properties
double normalizedLot = NormalizeLotSize(data.symbol, LotSize);
double bid = SymbolInfoDouble(data.symbol, SYMBOL_BID);
if(data.trade.Sell(normalizedLot, data.symbol, bid, 0, 0, "RSI Scalping Sell"))
{
ulong new_ticket = data.trade.ResultOrder();
if(new_ticket > 0)
{
if(PositionSelectByTicketSymbolAndMagic(new_ticket, data.symbol, MagicNumber))
{
data.position_ticket = new_ticket;
data.position_open = true;
data.current_position_type = POSITION_TYPE_SELL;
}
}
}
}
void ClosePosition(RSIScalpingData& data, int MagicNumber)
{
// First verify position still exists
if(!PositionExistsByMagic(data.symbol, MagicNumber))
{
// Position doesn't exist, reset tracking
data.position_open = false;
data.position_ticket = 0;
data.rsi_against_position = false;
data.bars_against_count = 0;
return;
}
// Try to close by ticket first (more reliable)
bool closed = false;
if(data.position_ticket > 0)
{
if(PositionSelectByTicket(data.position_ticket))
{
// Verify it's our position
if(PositionGetString(POSITION_SYMBOL) == data.symbol &&
PositionGetInteger(POSITION_MAGIC) == MagicNumber)
{
closed = data.trade.PositionClose(data.position_ticket);
if(!closed)
{
Print("RSIScalping: Failed to close position by ticket ", data.position_ticket,
" - Error: ", data.trade.ResultRetcode(), " (", data.trade.ResultRetcodeDescription(), ")");
}
}
}
}
// If ticket method failed, try magic number method
if(!closed)
{
closed = ClosePositionByMagic(data.trade, data.symbol, MagicNumber);
if(!closed)
{
Print("RSIScalping: Failed to close position by magic number for '", data.symbol,
"' - Error: ", data.trade.ResultRetcode(), " (", data.trade.ResultRetcodeDescription(), ")");
}
}
// Verify position is actually closed
if(closed)
{
// Wait a moment and verify
Sleep(50);
if(!PositionExistsByMagic(data.symbol, MagicNumber))
{
data.position_open = false;
data.position_ticket = 0;
data.rsi_against_position = false;
data.bars_against_count = 0;
Print("RSIScalping: Position successfully closed for '", data.symbol, "'");
}
else
{
Print("RSIScalping: Warning - Close returned success but position still exists for '", data.symbol, "'");
// Try one more time
Sleep(100);
if(PositionExistsByMagic(data.symbol, MagicNumber))
{
ClosePositionByMagic(data.trade, data.symbol, MagicNumber);
}
// Reset tracking anyway to prevent getting stuck
data.position_open = false;
data.position_ticket = 0;
data.rsi_against_position = false;
data.bars_against_count = 0;
}
}
else
{
// Close failed, but reset tracking to prevent getting stuck
// The position might have been closed externally
data.position_open = false;
data.position_ticket = 0;
data.rsi_against_position = false;
data.bars_against_count = 0;
}
}
void ProcessRSIScalping(RSIScalpingData& data, string symbol, ENUM_TIMEFRAMES TimeFrame, int RSI_Period,
ENUM_APPLIED_PRICE RSI_Applied_Price, double RSI_Overbought,
double RSI_Oversold, double RSI_Target_Buy, double RSI_Target_Sell,
int BarsToWait, double LotSize, int MagicNumber,
bool UseReversalEscape, int ReversalATRPeriod, double ReversalAdverseAtrMult,
int ReversalSignsRequired, double ReversalRsiVelocity, double ReversalBodyAtrMult,
bool UseTrailingStop, double TrailingStopDistancePoints, double TrailingActivationPoints)
{
// Skip if not initialized (symbol not available)
if(!data.isInitialized)
return;
data.symbol = symbol; // Update symbol in case it changed
if(Bars(data.symbol, TimeFrame) < RSI_Period + 2)
return;
const datetime current_bar_time = iTime(data.symbol, TimeFrame, 0);
const bool new_bar = (current_bar_time != data.last_bar_time);
const bool in_pos = data.position_open || PositionExistsByMagic(data.symbol, MagicNumber);
if(!in_pos && !new_bar)
return;
if(!UpdateRSI(data))
return;
if(in_pos && UseReversalEscape)
RS_TryReversalEscape(data, TimeFrame, MagicNumber, ReversalATRPeriod, ReversalAdverseAtrMult,
ReversalSignsRequired, ReversalRsiVelocity, ReversalBodyAtrMult);
if(in_pos)
RS_ApplyTrailingStop(data, MagicNumber, UseTrailingStop,
TrailingStopDistancePoints, TrailingActivationPoints);
if(!new_bar)
return;
data.last_bar_time = current_bar_time;
CheckExistingPosition(data, TimeFrame, MagicNumber, RSI_Oversold, RSI_Overbought,
RSI_Target_Buy, RSI_Target_Sell, BarsToWait);
if(!data.position_open && !PositionExistsByMagic(data.symbol, MagicNumber))
{
CheckEntrySignals(data, TimeFrame, MagicNumber, RSI_Oversold, RSI_Overbought, LotSize);
}
}
//+------------------------------------------------------------------+
@@ -1,336 +0,0 @@
//+------------------------------------------------------------------+
//| RSISecretSauceStrategy.mqh |
//| Cluster-0 orchestrator: RSI leave extreme then peak/bottom entry |
//+------------------------------------------------------------------+
#ifndef RSI_SECRET_SAUCE_STRATEGY_MQH
#define RSI_SECRET_SAUCE_STRATEGY_MQH
#include <Trade/Trade.mqh>
#include <Trade/PositionInfo.mqh>
struct RSISecretSauceOrcData
{
string actualSymbol;
bool isInitialized;
CTrade trade;
CPositionInfo positionInfo;
int rsiHandle;
int atrHandle;
double rsiBuffer[];
double atrBuffer[];
double highBuffer[];
double lowBuffer[];
bool rsiWasOverbought;
bool rsiWasOversold;
bool rsiBackInRange;
datetime lastRSIExitTime;
datetime lastRSIReentryTime;
datetime lastTradeTime;
datetime lastBarTime;
};
bool RSS_UpdateIndicators(RSISecretSauceOrcData &d)
{
int rsiBarsNeeded = RSS_RSILookback + 5;
if(CopyBuffer(d.rsiHandle, 0, 0, rsiBarsNeeded, d.rsiBuffer) < rsiBarsNeeded)
return false;
if(CopyBuffer(d.atrHandle, 0, 0, 2, d.atrBuffer) < 2)
return false;
if(CopyHigh(d.actualSymbol, RSS_Timeframe, 0, RSS_SwingLookback + 5, d.highBuffer) < RSS_SwingLookback + 5)
return false;
if(CopyLow(d.actualSymbol, RSS_Timeframe, 0, RSS_SwingLookback + 5, d.lowBuffer) < RSS_SwingLookback + 5)
return false;
return true;
}
void RSS_UpdateRSIState(RSISecretSauceOrcData &d)
{
double rsiCurrent = d.rsiBuffer[0];
double rsiPrev = d.rsiBuffer[1];
if(rsiPrev >= RSS_RSIOverbought && rsiCurrent < RSS_RSIOverbought)
{
d.rsiWasOverbought = true;
d.rsiBackInRange = true;
d.lastRSIExitTime = TimeCurrent();
d.lastRSIReentryTime = TimeCurrent();
}
if(rsiPrev <= RSS_RSIOversold && rsiCurrent > RSS_RSIOversold)
{
d.rsiWasOversold = true;
d.rsiBackInRange = true;
d.lastRSIExitTime = TimeCurrent();
d.lastRSIReentryTime = TimeCurrent();
}
if(rsiCurrent >= RSS_RSIOverbought)
{
d.rsiWasOverbought = false;
d.rsiBackInRange = false;
}
if(rsiCurrent <= RSS_RSIOversold)
{
d.rsiWasOversold = false;
d.rsiBackInRange = false;
}
}
bool RSS_IsRSIPeak(RSISecretSauceOrcData &d)
{
if(ArraySize(d.rsiBuffer) < RSS_PeakBars + 2)
return false;
double currentRSI = d.rsiBuffer[0];
bool isPeak = true;
for(int i = 1; i <= RSS_PeakBars; i++)
{
if(d.rsiBuffer[i] >= currentRSI)
{
isPeak = false;
break;
}
}
if(d.rsiBuffer[1] >= currentRSI)
isPeak = false;
return isPeak;
}
bool RSS_IsRSIBottom(RSISecretSauceOrcData &d)
{
if(ArraySize(d.rsiBuffer) < RSS_PeakBars + 2)
return false;
double currentRSI = d.rsiBuffer[0];
bool isBottom = true;
for(int i = 1; i <= RSS_PeakBars; i++)
{
if(d.rsiBuffer[i] <= currentRSI)
{
isBottom = false;
break;
}
}
if(d.rsiBuffer[1] <= currentRSI)
isBottom = false;
return isBottom;
}
double RSS_GetSwingStopLoss(RSISecretSauceOrcData &d, double currentPrice, ENUM_POSITION_TYPE type)
{
if(type == POSITION_TYPE_BUY)
{
double lowestLow = d.lowBuffer[0];
for(int i = 1; i < RSS_SwingLookback && i < ArraySize(d.lowBuffer); i++)
{
if(d.lowBuffer[i] < lowestLow)
lowestLow = d.lowBuffer[i];
}
return lowestLow;
}
double highestHigh = d.highBuffer[0];
for(int i = 1; i < RSS_SwingLookback && i < ArraySize(d.highBuffer); i++)
{
if(d.highBuffer[i] > highestHigh)
highestHigh = d.highBuffer[i];
}
return highestHigh;
}
bool RSS_CalculateStops(RSISecretSauceOrcData &d, double price, ENUM_POSITION_TYPE type, double &sl, double &tp)
{
double atrValue = d.atrBuffer[0];
if(atrValue <= 0)
atrValue = price * 0.01;
double slDistance = atrValue * RSS_StopLossATR;
double tpDistance = atrValue * RSS_TakeProfitATR;
int digits = (int)SymbolInfoInteger(d.actualSymbol, SYMBOL_DIGITS);
double point = SymbolInfoDouble(d.actualSymbol, SYMBOL_POINT);
int stopsLevel = (int)SymbolInfoInteger(d.actualSymbol, SYMBOL_TRADE_STOPS_LEVEL);
double minStopDistance = MathMax(stopsLevel * point, point * 10);
if(RSS_UseSwingStopLoss)
{
double swingStop = RSS_GetSwingStopLoss(d, price, type);
if(swingStop > 0)
{
if(type == POSITION_TYPE_BUY)
{
if(swingStop < price && (price - swingStop) > minStopDistance)
slDistance = price - swingStop;
}
else
{
if(swingStop > price && (swingStop - price) > minStopDistance)
slDistance = swingStop - price;
}
}
}
if(slDistance < minStopDistance)
slDistance = minStopDistance;
if(tpDistance < minStopDistance)
tpDistance = minStopDistance;
if(type == POSITION_TYPE_BUY)
{
sl = NormalizeDouble(price - slDistance, digits);
tp = NormalizeDouble(price + tpDistance, digits);
}
else
{
sl = NormalizeDouble(price + slDistance, digits);
tp = NormalizeDouble(price - tpDistance, digits);
}
return true;
}
bool RSS_CanOpenNewPosition(RSISecretSauceOrcData &d)
{
int positionCount = 0;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(d.positionInfo.SelectByIndex(i))
{
if(d.positionInfo.Symbol() == d.actualSymbol && d.positionInfo.Magic() == RSS_MagicNumber)
positionCount++;
}
}
if(positionCount >= RSS_MaxPositions)
return false;
if(d.lastTradeTime > 0)
{
int barsSince = Bars(d.actualSymbol, RSS_Timeframe, d.lastTradeTime, TimeCurrent());
if(barsSince < RSS_MinBarsBetweenTrades)
return false;
}
return true;
}
void RSS_OpenPosition(RSISecretSauceOrcData &d, ENUM_POSITION_TYPE type, const double lotSize)
{
double price = (type == POSITION_TYPE_BUY) ?
SymbolInfoDouble(d.actualSymbol, SYMBOL_ASK) :
SymbolInfoDouble(d.actualSymbol, SYMBOL_BID);
if(price <= 0)
return;
double sl = 0.0, tp = 0.0;
if(!RSS_CalculateStops(d, price, type, sl, tp))
return;
string comment = "RSI_Secret_" + (type == POSITION_TYPE_BUY ? "LONG" : "SHORT");
bool result = false;
if(type == POSITION_TYPE_BUY)
result = d.trade.Buy(lotSize, d.actualSymbol, 0, sl, tp, comment);
else
result = d.trade.Sell(lotSize, d.actualSymbol, 0, sl, tp, comment);
if(result)
{
d.lastTradeTime = TimeCurrent();
if(type == POSITION_TYPE_BUY)
d.rsiWasOverbought = false;
else
d.rsiWasOversold = false;
d.rsiBackInRange = false;
}
}
void RSS_CheckEntrySignals(RSISecretSauceOrcData &d, const double lotSize)
{
if(d.rsiWasOverbought && d.rsiBackInRange)
{
if(d.rsiBuffer[0] < RSS_RSIOverbought && RSS_IsRSIPeak(d))
RSS_OpenPosition(d, POSITION_TYPE_BUY, lotSize);
}
if(d.rsiWasOversold && d.rsiBackInRange)
{
if(d.rsiBuffer[0] > RSS_RSIOversold && RSS_IsRSIBottom(d))
RSS_OpenPosition(d, POSITION_TYPE_SELL, lotSize);
}
}
bool InitRSISecretSauce(RSISecretSauceOrcData &d, const string symbol)
{
d.isInitialized = false;
d.rsiHandle = INVALID_HANDLE;
d.atrHandle = INVALID_HANDLE;
d.rsiWasOverbought = false;
d.rsiWasOversold = false;
d.rsiBackInRange = false;
d.lastRSIExitTime = 0;
d.lastRSIReentryTime = 0;
d.lastTradeTime = 0;
d.lastBarTime = 0;
d.actualSymbol = symbol;
StringTrimLeft(d.actualSymbol);
StringTrimRight(d.actualSymbol);
if(StringLen(d.actualSymbol) == 0)
d.actualSymbol = _Symbol;
if(!SymbolSelect(d.actualSymbol, true))
{
Print("RSISecretSauce: symbol not available '", d.actualSymbol, "'");
return false;
}
d.rsiHandle = iRSI(d.actualSymbol, RSS_Timeframe, RSS_RSIPeriod, PRICE_CLOSE);
d.atrHandle = iATR(d.actualSymbol, RSS_Timeframe, RSS_ATRPeriod);
if(d.rsiHandle == INVALID_HANDLE || d.atrHandle == INVALID_HANDLE)
return false;
ArraySetAsSeries(d.rsiBuffer, true);
ArraySetAsSeries(d.atrBuffer, true);
ArraySetAsSeries(d.highBuffer, true);
ArraySetAsSeries(d.lowBuffer, true);
d.trade.SetExpertMagicNumber(RSS_MagicNumber);
d.trade.SetDeviationInPoints(RSS_Slippage);
d.trade.SetTypeFilling(ORDER_FILLING_FOK);
d.isInitialized = true;
return true;
}
void DeinitRSISecretSauce(RSISecretSauceOrcData &d)
{
if(d.rsiHandle != INVALID_HANDLE)
IndicatorRelease(d.rsiHandle);
if(d.atrHandle != INVALID_HANDLE)
IndicatorRelease(d.atrHandle);
d.rsiHandle = INVALID_HANDLE;
d.atrHandle = INVALID_HANDLE;
d.isInitialized = false;
}
void ProcessRSISecretSauce(RSISecretSauceOrcData &d, const double lotSize)
{
if(!d.isInitialized)
return;
int requiredBars = MathMax(RSS_RSILookback, RSS_SwingLookback) + 10;
if(Bars(d.actualSymbol, RSS_Timeframe) < requiredBars)
return;
datetime currentBarTime = iTime(d.actualSymbol, RSS_Timeframe, 0);
if(currentBarTime == d.lastBarTime)
return;
d.lastBarTime = currentBarTime;
if(!RSS_UpdateIndicators(d))
return;
RSS_UpdateRSIState(d);
if(RSS_CanOpenNewPosition(d))
RSS_CheckEntrySignals(d, lotSize);
}
#endif
@@ -1,318 +0,0 @@
//+------------------------------------------------------------------+
//| SimpleTrendlineStrategy.mqh |
//+------------------------------------------------------------------+
#ifndef SIMPLE_TRENDLINE_STRATEGY_MQH
#define SIMPLE_TRENDLINE_STRATEGY_MQH
struct SimpleTrendlineModel
{
datetime t1;
datetime t2;
datetime t3;
double a;
double b;
bool valid;
};
struct SimpleTrendlineData
{
string symbol;
bool isInitialized;
CTrade trade;
ENUM_TIMEFRAMES signalTF;
ENUM_TIMEFRAMES higherTF;
int maPeriod;
ENUM_MA_METHOD maMethod;
ENUM_APPLIED_PRICE appliedPrice;
int htfBarsToScan;
double touchTolerancePoints;
double breakBufferPoints;
ulong magic;
bool drawTrendline;
int maHandle;
datetime lastSignalBarTime;
string lineName;
};
double ST_NormalizeVolume(const string sym, double vol)
{
double minLot = SymbolInfoDouble(sym, SYMBOL_VOLUME_MIN);
double maxLot = SymbolInfoDouble(sym, SYMBOL_VOLUME_MAX);
double step = SymbolInfoDouble(sym, SYMBOL_VOLUME_STEP);
if(step > 0.0)
vol = MathFloor(vol / step) * step;
if(vol < minLot)
vol = minLot;
if(vol > maxLot)
vol = maxLot;
return vol;
}
bool ST_GetPosition(const string sym, const ulong magic, ENUM_POSITION_TYPE &type, double &volume)
{
if(!PositionSelectByMagic(sym, magic))
return false;
type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
volume = PositionGetDouble(POSITION_VOLUME);
return true;
}
int ST_FindRecentCrossPoints(SimpleTrendlineData &d, datetime &times[], double &prices[])
{
ArrayResize(times, 0);
ArrayResize(prices, 0);
if(d.maHandle == INVALID_HANDLE)
return 0;
int needBars = MathMax(d.htfBarsToScan, d.maPeriod + 20);
MqlRates rates[];
double maBuf[];
ArraySetAsSeries(rates, true);
ArraySetAsSeries(maBuf, true);
int copiedRates = CopyRates(d.symbol, d.higherTF, 0, needBars, rates);
int copiedMa = CopyBuffer(d.maHandle, 0, 0, needBars, maBuf);
if(copiedRates <= 5 || copiedMa <= 5)
return 0;
int bars = MathMin(copiedRates, copiedMa);
for(int i = 2; i < bars - 1; i++)
{
double d0 = rates[i].close - maBuf[i];
double d1 = rates[i + 1].close - maBuf[i + 1];
if(d0 == 0.0 || d1 == 0.0 || (d0 * d1 < 0.0))
{
int n = ArraySize(times);
ArrayResize(times, n + 1);
ArrayResize(prices, n + 1);
times[n] = rates[i].time;
prices[n] = rates[i].close;
if(ArraySize(times) >= 3)
break;
}
}
return ArraySize(times);
}
bool ST_BuildTrendline(SimpleTrendlineData &d, SimpleTrendlineModel &m)
{
m.valid = false;
datetime ts[];
double ps[];
if(ST_FindRecentCrossPoints(d, ts, ps) < 3)
return false;
datetime tOld[3];
double pOld[3];
for(int i = 0; i < 3; i++)
{
tOld[i] = ts[2 - i];
pOld[i] = ps[2 - i];
}
long t0 = (long)tOld[0];
double x1 = 0.0;
double x2 = (double)((long)tOld[1] - t0);
double x3 = (double)((long)tOld[2] - t0);
double y1 = pOld[0];
double y2 = pOld[1];
double y3 = pOld[2];
double sx = x1 + x2 + x3;
double sy = y1 + y2 + y3;
double sxx = x1 * x1 + x2 * x2 + x3 * x3;
double sxy = x1 * y1 + x2 * y2 + x3 * y3;
double den = 3.0 * sxx - sx * sx;
if(MathAbs(den) < 1e-10)
return false;
m.a = (3.0 * sxy - sx * sy) / den;
m.b = (sy - m.a * sx) / 3.0;
m.t1 = tOld[0];
m.t2 = tOld[1];
m.t3 = tOld[2];
m.valid = true;
return true;
}
double ST_LinePriceAt(const SimpleTrendlineModel &m, const datetime t)
{
if(!m.valid)
return 0.0;
double x = (double)((long)t - (long)m.t1);
return m.a * x + m.b;
}
void ST_DrawTrendline(SimpleTrendlineData &d, const SimpleTrendlineModel &m)
{
if(!d.drawTrendline || !m.valid || d.symbol != _Symbol)
return;
datetime tStart = m.t1;
datetime tEnd = iTime(d.symbol, d.signalTF, 0);
if(tEnd <= tStart)
tEnd = m.t3 + PeriodSeconds(d.signalTF) * 20;
double pStart = ST_LinePriceAt(m, tStart);
double pEnd = ST_LinePriceAt(m, tEnd);
if(ObjectFind(0, d.lineName) < 0)
ObjectCreate(0, d.lineName, OBJ_TREND, 0, tStart, pStart, tEnd, pEnd);
else
{
ObjectMove(0, d.lineName, 0, tStart, pStart);
ObjectMove(0, d.lineName, 1, tEnd, pEnd);
}
ObjectSetInteger(0, d.lineName, OBJPROP_RAY_RIGHT, true);
ObjectSetInteger(0, d.lineName, OBJPROP_COLOR, clrGold);
ObjectSetInteger(0, d.lineName, OBJPROP_WIDTH, 2);
}
void ST_TryExitOnBreak(SimpleTrendlineData &d, const SimpleTrendlineModel &m)
{
ENUM_POSITION_TYPE posType;
double vol;
if(!ST_GetPosition(d.symbol, d.magic, posType, vol))
return;
double close1 = iClose(d.symbol, d.signalTF, 1);
datetime t1 = iTime(d.symbol, d.signalTF, 1);
double line1 = ST_LinePriceAt(m, t1);
double buf = d.breakBufferPoints * SymbolInfoDouble(d.symbol, SYMBOL_POINT);
bool closePos = false;
if(posType == POSITION_TYPE_BUY && close1 < (line1 - buf))
closePos = true;
if(posType == POSITION_TYPE_SELL && close1 > (line1 + buf))
closePos = true;
if(closePos)
ClosePositionByMagic(d.trade, d.symbol, d.magic);
}
void ST_TryPullbackEntry(SimpleTrendlineData &d, const SimpleTrendlineModel &m, const double lots)
{
if(PositionExistsByMagic(d.symbol, d.magic))
return;
MqlRates b1[], b2[];
ArraySetAsSeries(b1, true);
ArraySetAsSeries(b2, true);
if(CopyRates(d.symbol, d.signalTF, 1, 1, b1) != 1)
return;
if(CopyRates(d.symbol, d.signalTF, 2, 1, b2) != 1)
return;
if(ArraySize(b1) < 1 || ArraySize(b2) < 1)
return;
double line1 = ST_LinePriceAt(m, b1[0].time);
double tol = d.touchTolerancePoints * SymbolInfoDouble(d.symbol, SYMBOL_POINT);
bool upTrend = (m.a > 0.0);
bool downTrend = (m.a < 0.0);
double vol = ST_NormalizeVolume(d.symbol, lots);
if(upTrend)
{
bool touched = (b1[0].low <= (line1 + tol));
bool reclaim = (b1[0].close > line1);
bool bullish = (b1[0].close > b1[0].open);
bool stillHealthy = (b2[0].close >= ST_LinePriceAt(m, b2[0].time) - tol);
if(touched && reclaim && bullish && stillHealthy)
{
if(!d.trade.Buy(vol, d.symbol, 0.0, 0.0, 0.0, "SimpleTrendline BUY"))
Print("SimpleTrendline BUY failed [", d.symbol, "] retcode=", d.trade.ResultRetcode(), " ", d.trade.ResultRetcodeDescription());
}
}
else if(downTrend)
{
bool touched = (b1[0].high >= (line1 - tol));
bool reject = (b1[0].close < line1);
bool bearish = (b1[0].close < b1[0].open);
bool stillWeak = (b2[0].close <= ST_LinePriceAt(m, b2[0].time) + tol);
if(touched && reject && bearish && stillWeak)
{
if(!d.trade.Sell(vol, d.symbol, 0.0, 0.0, 0.0, "SimpleTrendline SELL"))
Print("SimpleTrendline SELL failed [", d.symbol, "] retcode=", d.trade.ResultRetcode(), " ", d.trade.ResultRetcodeDescription());
}
}
}
bool InitSimpleTrendline(SimpleTrendlineData &d,
const string symbol,
const ENUM_TIMEFRAMES signalTF,
const ENUM_TIMEFRAMES higherTF,
const int maPeriod,
const ENUM_MA_METHOD maMethod,
const ENUM_APPLIED_PRICE appliedPrice,
const int htfBarsToScan,
const double touchTolerancePoints,
const double breakBufferPoints,
const ulong magic,
const bool drawTrendline)
{
d.isInitialized = false;
d.symbol = symbol;
StringTrimLeft(d.symbol);
StringTrimRight(d.symbol);
if(StringLen(d.symbol) == 0)
d.symbol = _Symbol;
if(!SymbolSelect(d.symbol, true))
return false;
d.signalTF = signalTF;
d.higherTF = higherTF;
d.maPeriod = maPeriod;
d.maMethod = maMethod;
d.appliedPrice = appliedPrice;
d.htfBarsToScan = htfBarsToScan;
d.touchTolerancePoints = touchTolerancePoints;
d.breakBufferPoints = breakBufferPoints;
d.magic = magic;
d.drawTrendline = drawTrendline;
d.lastSignalBarTime = 0;
d.lineName = "SimpleTrendline_" + d.symbol + "_" + IntegerToString((int)d.magic);
d.trade.SetExpertMagicNumber((long)d.magic);
d.trade.SetTypeFillingBySymbol(d.symbol);
d.trade.SetDeviationInPoints(20);
d.maHandle = iMA(d.symbol, d.higherTF, d.maPeriod, 0, d.maMethod, d.appliedPrice);
if(d.maHandle == INVALID_HANDLE)
return false;
d.isInitialized = true;
return true;
}
void DeinitSimpleTrendline(SimpleTrendlineData &d)
{
if(d.maHandle != INVALID_HANDLE)
IndicatorRelease(d.maHandle);
d.maHandle = INVALID_HANDLE;
if(ObjectFind(0, d.lineName) >= 0)
ObjectDelete(0, d.lineName);
d.isInitialized = false;
}
void ProcessSimpleTrendline(SimpleTrendlineData &d, const double lots)
{
if(!d.isInitialized)
return;
datetime bar0 = iTime(d.symbol, d.signalTF, 0);
if(bar0 == 0 || bar0 == d.lastSignalBarTime)
return;
d.lastSignalBarTime = bar0;
SimpleTrendlineModel m;
if(!ST_BuildTrendline(d, m))
return;
ST_DrawTrendline(d, m);
ST_TryExitOnBreak(d, m);
ST_TryPullbackEntry(d, m, lots);
}
#endif // SIMPLE_TRENDLINE_STRATEGY_MQH
@@ -1,509 +0,0 @@
//+------------------------------------------------------------------+
//| SuperEMAStrategy.mqh — EMA + CCI + MACD (United EA module) |
//+------------------------------------------------------------------+
#ifndef SUPER_EMA_STRATEGY_MQH
#define SUPER_EMA_STRATEGY_MQH
#include <Trade/Trade.mqh>
enum ENUM_SE_ENTRY_STYLE
{
SE_ENTRY_CCIZERO_MACD = 0,
SE_ENTRY_LAMBERT = 1,
SE_ENTRY_PULLBACK = 2
};
struct SuperEMAData
{
string symbol;
ENUM_TIMEFRAMES tf;
datetime lastBarTime;
CTrade trade;
bool isInitialized;
int slippagePoints;
int magic;
int emaFast;
int emaMid;
int emaSlow;
int emaTrendBars;
int cciPeriod;
double cciOverbought;
double cciOversold;
int pullbackCciLookback;
int macdFast;
int macdSlow;
int macdSignal;
ENUM_SE_ENTRY_STYLE entryStyle;
bool oneTradeOnly;
bool useStructuralSL;
double slBufferPoints;
bool exitOnTrendFlip;
bool exitOnMacdFlip;
bool exitOnCciZeroCross;
int maxHoldingBars;
bool exitBelowMidEma;
bool debugLogs;
};
void SuperEMA_Log(SuperEMAData &d, const string s)
{
if(d.debugLogs)
Print("[SuperEMA] ", s);
}
double SuperEMA_Point(const SuperEMAData &d)
{
double pt = SymbolInfoDouble(d.symbol, SYMBOL_POINT);
return (pt > 0.0 ? pt : _Point);
}
bool SuperEMA_IsNewBar(SuperEMAData &d)
{
datetime t = iTime(d.symbol, d.tf, 0);
if(t <= 0 || t == d.lastBarTime)
return false;
d.lastBarTime = t;
return true;
}
double SuperEMA_EmaAt(SuperEMAData &d, const int period, const int shift)
{
int h = iMA(d.symbol, d.tf, period, 0, MODE_EMA, PRICE_CLOSE);
if(h == INVALID_HANDLE)
return 0.0;
double b[1];
if(CopyBuffer(h, 0, shift, 1, b) <= 0)
{
IndicatorRelease(h);
return 0.0;
}
IndicatorRelease(h);
return b[0];
}
double SuperEMA_CciAt(SuperEMAData &d, const int shift)
{
int h = iCCI(d.symbol, d.tf, d.cciPeriod, PRICE_TYPICAL);
if(h == INVALID_HANDLE)
return 0.0;
double b[1];
if(CopyBuffer(h, 0, shift, 1, b) <= 0)
{
IndicatorRelease(h);
return 0.0;
}
IndicatorRelease(h);
return b[0];
}
bool SuperEMA_MacdHistAt(SuperEMAData &d, const int shift, double &hist)
{
int h = iMACD(d.symbol, d.tf, d.macdFast, d.macdSlow, d.macdSignal, PRICE_CLOSE);
if(h == INVALID_HANDLE)
return false;
double mainLine[1], sigLine[1];
if(CopyBuffer(h, 0, shift, 1, mainLine) <= 0 || CopyBuffer(h, 1, shift, 1, sigLine) <= 0)
{
IndicatorRelease(h);
return false;
}
IndicatorRelease(h);
hist = mainLine[0] - sigLine[0];
return true;
}
bool SuperEMA_TrendUp(SuperEMAData &d, const int sh)
{
double c = iClose(d.symbol, d.tf, sh);
double emaS = SuperEMA_EmaAt(d, d.emaSlow, sh);
return (emaS > 0.0 && c > emaS);
}
bool SuperEMA_TrendDown(SuperEMAData &d, const int sh)
{
double c = iClose(d.symbol, d.tf, sh);
double emaS = SuperEMA_EmaAt(d, d.emaSlow, sh);
return (emaS > 0.0 && c < emaS);
}
bool SuperEMA_CciCrossAboveZero(SuperEMAData &d)
{
double c1 = SuperEMA_CciAt(d, 1);
double c2 = SuperEMA_CciAt(d, 2);
return (c2 <= 0.0 && c1 > 0.0);
}
bool SuperEMA_CciCrossBelowZero(SuperEMAData &d)
{
double c1 = SuperEMA_CciAt(d, 1);
double c2 = SuperEMA_CciAt(d, 2);
return (c2 >= 0.0 && c1 < 0.0);
}
bool SuperEMA_CciCrossAbove100(SuperEMAData &d)
{
double c1 = SuperEMA_CciAt(d, 1);
double c2 = SuperEMA_CciAt(d, 2);
return (c2 < d.cciOverbought && c1 > d.cciOverbought);
}
bool SuperEMA_CciCrossBelowMinus100(SuperEMAData &d)
{
double c1 = SuperEMA_CciAt(d, 1);
double c2 = SuperEMA_CciAt(d, 2);
return (c2 > d.cciOversold && c1 < d.cciOversold);
}
bool SuperEMA_HadCciOversoldRecently(SuperEMAData &d)
{
for(int i = 2; i <= d.pullbackCciLookback + 1; i++)
{
double v = SuperEMA_CciAt(d, i);
if(v <= d.cciOversold)
return true;
}
return false;
}
bool SuperEMA_HadCciOverboughtRecently(SuperEMAData &d)
{
for(int i = 2; i <= d.pullbackCciLookback + 1; i++)
{
double v = SuperEMA_CciAt(d, i);
if(v >= d.cciOverbought)
return true;
}
return false;
}
bool SuperEMA_PullbackNearFastEmaLong(SuperEMAData &d)
{
double emaF = SuperEMA_EmaAt(d, d.emaFast, 1);
double lo = iLow(d.symbol, d.tf, 1);
if(emaF <= 0.0)
return false;
const double pt = SuperEMA_Point(d);
return (lo <= emaF + d.slBufferPoints * pt * 3.0);
}
bool SuperEMA_PullbackNearFastEmaShort(SuperEMAData &d)
{
double emaF = SuperEMA_EmaAt(d, d.emaFast, 1);
double hi = iHigh(d.symbol, d.tf, 1);
if(emaF <= 0.0)
return false;
const double pt = SuperEMA_Point(d);
return (hi >= emaF - d.slBufferPoints * pt * 3.0);
}
int SuperEMA_PositionsByMagic(SuperEMAData &d)
{
int n = 0;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong t = PositionGetTicket(i);
if(t == 0)
continue;
if(!PositionSelectByTicket(t))
continue;
if(PositionGetString(POSITION_SYMBOL) == d.symbol && (int)PositionGetInteger(POSITION_MAGIC) == d.magic)
n++;
}
return n;
}
void SuperEMA_ComputeSLTP(SuperEMAData &d, const bool isBuy, double &sl, double &tp)
{
sl = 0.0;
tp = 0.0;
if(!d.useStructuralSL)
return;
double emaM = SuperEMA_EmaAt(d, d.emaMid, d.emaTrendBars);
double buf = d.slBufferPoints * SuperEMA_Point(d);
if(isBuy)
sl = emaM - buf;
else
sl = emaM + buf;
}
int SuperEMA_BarsSinceOpen(SuperEMAData &d, const datetime openTime)
{
if(openTime <= 0)
return 0;
int sh = iBarShift(d.symbol, d.tf, openTime, false);
if(sh < 0)
return 999999;
return sh;
}
void SuperEMA_CloseTicket(SuperEMAData &d, const ulong ticket, const string reason)
{
#ifdef UNITED_MARTINGALE_NO_SELF_CLOSE
return;
#endif
d.trade.SetExpertMagicNumber(d.magic);
if(d.trade.PositionClose(ticket))
SuperEMA_Log(d, "Close: " + reason);
}
void SuperEMA_ManageExits(SuperEMAData &d)
{
#ifdef UNITED_MARTINGALE_NO_SELF_CLOSE
return;
#endif
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket == 0)
continue;
if(!PositionSelectByTicket(ticket))
continue;
if(PositionGetString(POSITION_SYMBOL) != d.symbol)
continue;
if((int)PositionGetInteger(POSITION_MAGIC) != d.magic)
continue;
ENUM_POSITION_TYPE ptype = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
datetime openTime = (datetime)PositionGetInteger(POSITION_TIME);
double h1 = 0.0;
if(!SuperEMA_MacdHistAt(d, 1, h1))
continue;
bool closeLong = false;
bool closeShort = false;
string reason = "";
if(d.maxHoldingBars > 0)
{
int held = SuperEMA_BarsSinceOpen(d, openTime);
if(held >= d.maxHoldingBars)
{
if(ptype == POSITION_TYPE_BUY)
closeLong = true;
else
closeShort = true;
reason = "time stop (max bars)";
}
}
if(ptype == POSITION_TYPE_BUY)
{
if(d.exitOnTrendFlip && SuperEMA_TrendDown(d, d.emaTrendBars))
{
closeLong = true;
reason = "trend flip (below slow EMA)";
}
if(d.exitOnMacdFlip && h1 < 0.0)
{
closeLong = true;
reason = "MACD histogram < 0";
}
if(d.exitOnCciZeroCross && SuperEMA_CciCrossBelowZero(d))
{
closeLong = true;
reason = "CCI crossed below zero";
}
if(d.exitBelowMidEma)
{
double c = iClose(d.symbol, d.tf, 1);
double emaM = SuperEMA_EmaAt(d, d.emaMid, 1);
if(emaM > 0.0 && c < emaM)
{
closeLong = true;
reason = "close below mid EMA";
}
}
if(closeLong)
SuperEMA_CloseTicket(d, ticket, reason);
}
else if(ptype == POSITION_TYPE_SELL)
{
if(d.exitOnTrendFlip && SuperEMA_TrendUp(d, d.emaTrendBars))
{
closeShort = true;
reason = "trend flip (above slow EMA)";
}
if(d.exitOnMacdFlip && h1 > 0.0)
{
closeShort = true;
reason = "MACD histogram > 0";
}
if(d.exitOnCciZeroCross && SuperEMA_CciCrossAboveZero(d))
{
closeShort = true;
reason = "CCI crossed above zero";
}
if(d.exitBelowMidEma)
{
double c = iClose(d.symbol, d.tf, 1);
double emaM = SuperEMA_EmaAt(d, d.emaMid, 1);
if(emaM > 0.0 && c > emaM)
{
closeShort = true;
reason = "close above mid EMA";
}
}
if(closeShort)
SuperEMA_CloseTicket(d, ticket, reason);
}
}
}
bool InitSuperEMA(SuperEMAData &d,
const string symbol,
const ENUM_TIMEFRAMES tf,
const int slippagePoints,
const int magic,
const int emaFast,
const int emaMid,
const int emaSlow,
const int emaTrendBars,
const int cciPeriod,
const double cciOverbought,
const double cciOversold,
const int pullbackCciLookback,
const int macdFast,
const int macdSlow,
const int macdSignal,
const ENUM_SE_ENTRY_STYLE entryStyle,
const bool oneTradeOnly,
const bool useStructuralSL,
const double slBufferPoints,
const bool exitOnTrendFlip,
const bool exitOnMacdFlip,
const bool exitOnCciZeroCross,
const int maxHoldingBars,
const bool exitBelowMidEma,
const bool debugLogs)
{
d.symbol = symbol;
if(StringLen(d.symbol) == 0)
d.symbol = _Symbol;
d.tf = tf;
d.lastBarTime = 0;
d.isInitialized = false;
d.slippagePoints = slippagePoints;
d.magic = magic;
d.emaFast = emaFast;
d.emaMid = emaMid;
d.emaSlow = emaSlow;
d.emaTrendBars = emaTrendBars;
d.cciPeriod = cciPeriod;
d.cciOverbought = cciOverbought;
d.cciOversold = cciOversold;
d.pullbackCciLookback = pullbackCciLookback;
d.macdFast = macdFast;
d.macdSlow = macdSlow;
d.macdSignal = macdSignal;
d.entryStyle = entryStyle;
d.oneTradeOnly = oneTradeOnly;
d.useStructuralSL = useStructuralSL;
d.slBufferPoints = slBufferPoints;
d.exitOnTrendFlip = exitOnTrendFlip;
d.exitOnMacdFlip = exitOnMacdFlip;
d.exitOnCciZeroCross = exitOnCciZeroCross;
d.maxHoldingBars = maxHoldingBars;
d.exitBelowMidEma = exitBelowMidEma;
d.debugLogs = debugLogs;
if(!SymbolSelect(d.symbol, true))
{
Print("SuperEMA: symbol not available: ", d.symbol);
return false;
}
d.trade.SetExpertMagicNumber(d.magic);
d.trade.SetDeviationInPoints(d.slippagePoints);
d.isInitialized = true;
return true;
}
void ProcessSuperEMA(SuperEMAData &d, const double lots)
{
if(!d.isInitialized)
return;
if(!SuperEMA_IsNewBar(d))
return;
SuperEMA_ManageExits(d);
// Same order as standalone SuperEMAXAUUSD: skip entry logic when flat is not allowed.
if(d.oneTradeOnly && SuperEMA_PositionsByMagic(d) > 0)
return;
const int sh = d.emaTrendBars;
double h1 = 0.0;
if(!SuperEMA_MacdHistAt(d, 1, h1))
return;
bool up = SuperEMA_TrendUp(d, sh);
bool dn = SuperEMA_TrendDown(d, sh);
bool wantBuy = false;
bool wantSell = false;
switch(d.entryStyle)
{
case SE_ENTRY_CCIZERO_MACD:
if(up && SuperEMA_CciCrossAboveZero(d) && h1 > 0.0)
wantBuy = true;
if(dn && SuperEMA_CciCrossBelowZero(d) && h1 < 0.0)
wantSell = true;
break;
case SE_ENTRY_LAMBERT:
if(up && SuperEMA_CciCrossAbove100(d) && h1 > 0.0)
wantBuy = true;
if(dn && SuperEMA_CciCrossBelowMinus100(d) && h1 < 0.0)
wantSell = true;
break;
case SE_ENTRY_PULLBACK:
if(up && SuperEMA_HadCciOversoldRecently(d) && SuperEMA_CciCrossAboveZero(d) && h1 > 0.0 && SuperEMA_PullbackNearFastEmaLong(d))
wantBuy = true;
if(dn && SuperEMA_HadCciOverboughtRecently(d) && SuperEMA_CciCrossBelowZero(d) && h1 < 0.0 && SuperEMA_PullbackNearFastEmaShort(d))
wantSell = true;
break;
}
if(!wantBuy && !wantSell)
return;
const double vol = United_NormalizeVolume(d.symbol, lots);
if(vol <= 0.0)
{
SuperEMA_Log(d, "Skip entry: normalized volume <= 0");
return;
}
MqlTick tick;
if(!SymbolInfoTick(d.symbol, tick))
return;
double sl = 0.0, tp = 0.0;
if(wantBuy && !wantSell)
{
#ifndef UNITED_MARTINGALE_NO_SELF_CLOSE
SuperEMA_ComputeSLTP(d, true, sl, tp);
#endif
if(d.trade.Buy(vol, d.symbol, tick.ask, sl, tp, "United SuperEMA long"))
SuperEMA_Log(d, StringFormat("BUY ask=%.5f sl=%.5f", tick.ask, sl));
}
else if(wantSell && !wantBuy)
{
#ifndef UNITED_MARTINGALE_NO_SELF_CLOSE
SuperEMA_ComputeSLTP(d, false, sl, tp);
#endif
if(d.trade.Sell(vol, d.symbol, tick.bid, sl, tp, "United SuperEMA short"))
SuperEMA_Log(d, StringFormat("SELL bid=%.5f sl=%.5f", tick.bid, sl));
}
}
void DeinitSuperEMA(SuperEMAData &d)
{
d.isInitialized = false;
}
#endif // SUPER_EMA_STRATEGY_MQH
-904
View File
@@ -1,904 +0,0 @@
//+------------------------------------------------------------------+
//| 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.20"
#property strict
#property description "LOT_* nominal at ORCH_ReferenceBalance; scale = balance/equity ÷ reference (clamped). No performance-evaluator ranking."
#include <Trade\Trade.mqh>
#include <Trade\PositionInfo.mqh>
#include <Indicators\Trend.mqh>
#include <Indicators\Volumes.mqh>
#include "MagicNumberHelpers.mqh"
#define UNITED_V2_DYNAMIC_LOTS
double g_DB_LotSize;
// Include strategy implementations early so structs are available
#include "Strategies/DarvasBoxStrategy.mqh"
#include "Strategies/EMASlopeDistanceStrategy.mqh"
#include "Strategies/RSICrossOverReversalStrategy.mqh"
#include "Strategies/RSIMidPointHijackStrategy.mqh"
#include "Strategies/RSIScalpingStrategy.mqh"
#include "Strategies/SuperEMAStrategy.mqh"
#include "Strategies/RSIReversalAsianStrategy.mqh"
#include "Strategies/RSIConsolidationStrategy.mqh"
#include "Strategies/SimpleTrendlineStrategy.mqh"
#include "Strategies/RSISecretSauceStrategy.mqh"
//+------------------------------------------------------------------+
//| Global Lot Size Variables (for dynamic lot sizing) |
//+------------------------------------------------------------------+
double g_ES_LotSize; // EMA Slope Distance lot size
double g_RC_LotSize; // RSI CrossOver Reversal lot size
double g_RM_LotSize; // RSI MidPoint Hijack lot size
double g_Pos_RS_APPL;
double g_Pos_RS_BTCUSD;
double g_Pos_RS_NVDA;
double g_Pos_RS_TSLA;
double g_Pos_RS_XAUUSD;
double g_Pos_RRA_EURUSD;
double g_Pos_RRA_AUDUSD;
double g_Pos_SE;
double g_Pos_RCO;
double g_Pos_ST_BTCUSD;
double g_Pos_ST_XAUUSD;
double g_RSS_LotSize;
bool United_MayOpenNewEntry(const string symbol, const ulong magic, const bool isBuy)
{
if(PositionExistsByMagic(symbol, magic))
return false;
return true;
}
//+------------------------------------------------------------------+
//| Strategy Enable/Disable Switches |
//+------------------------------------------------------------------+
input group "=== Strategy Enable/Disable ==="
input bool EnableDarvasBox = true;
input bool EnableEMASlopeDistance = true;
input bool EnableRSICrossOverReversal = true;
input bool EnableRSIMidPointHijack = false;
input bool EnableRSIScalpingAPPL = false;
input bool EnableRSIScalpingBTCUSD = false;
input bool EnableRSIScalpingNVDA = false;
input bool EnableRSIScalpingTSLA = false;
input bool EnableRSIScalpingXAUUSD = true;
input bool EnableSuperEMA = true;
input bool EnableRSIConsolidation = true;
input bool EnableRSIReversalAsianEURUSD = false;
input bool EnableRSIReversalAsianAUDUSD = false;
input bool EnableSimpleTrendlineBTCUSD = false;
input bool EnableSimpleTrendlineXAUUSD = true;
input bool EnableRSISecretSauce = false;
input group "=== Centralized Lot Size (Granular Per Robot) ==="
input double LOT_DB_DarvasBox = 0.04;
input double LOT_ES_EMASlopeDistance = 0.09;
input double LOT_RC_RSICrossOver = 0.1;
input double LOT_RM_RSIMidPointHijack = 0.01;
input double LOT_RS_APPL = 5.0;
input double LOT_RS_BTCUSD = 0.1;
input double LOT_RS_NVDA = 10.0;
input double LOT_RS_TSLA = 15.0;
input double LOT_RS_XAUUSD = 0.05;
input double LOT_RRA_EURUSD = 0.05;
input double LOT_RRA_AUDUSD = 0.08;
input double LOT_SE_SuperEMA = 0.02;
input double LOT_RCO_RSIConsolidation = 0.02;
input double LOT_ST_BTCUSD = 0.07;
input double LOT_ST_XAUUSD = 0.02;
input double LOT_RSS_SecretSauce = 0.01;
input group "=== Balance-based position sizing ==="
input bool ORCH_ScaleLotsByBalance = true;
input bool ORCH_UseEquityInsteadOfBalance = false;
input double ORCH_ReferenceBalance = 10000.0;
input double ORCH_MinBalanceScale = 0.1;
input double ORCH_MaxBalanceScale = 10.0;
//+------------------------------------------------------------------+
//| Strategy 1: DarvasBoxXAUUSD |
//+------------------------------------------------------------------+
input group "=== DarvasBox Strategy ==="
input string DB_Symbol = "XAU";
input int DB_BoxPeriod = 165;
input double DB_BoxDeviation = 30000; // Increased to allow larger ranges (was 25140)
input int DB_VolumeThreshold = 0; // Set to 0 to disable volume threshold check. Volume data from indicator used instead.
input double DB_StopLoss = 1665;
input double DB_TakeProfit = 3685;
input bool DB_EnableLogging = false;
input color DB_BoxColor = (color)16711680;
input int DB_BoxWidth = 1;
input ENUM_TIMEFRAMES DB_TrendTimeframe = PERIOD_H2;
input int DB_MA_Period = 125;
input ENUM_MA_METHOD DB_MA_Method = MODE_EMA;
input ENUM_APPLIED_PRICE DB_MA_Price = PRICE_WEIGHTED;
input double DB_TrendThreshold = 4.94;
input int DB_VolumeMA_Period = 110;
input double DB_VolumeThresholdMultiplier = 1.5;
input bool DB_UseVolumeSpikeFilter = true;
input bool DB_UseTrendFilter = true;
input int DB_MagicNumber = 135790;
//+------------------------------------------------------------------+
//| Strategy 2: EMASlopeDistanceCocktailXAUUSD |
//| PEPPERSTONE US: Gold symbol is typically "XAUUSD" or "GOLD" |
//+------------------------------------------------------------------+
input group "=== EMA Slope Distance Strategy ==="
input string ES_Symbol = "XAU";
input int ES_EMA_Periode = 46;
input double ES_PreisSchwelle = 600.0;
input double ES_SteigungSchwelle = 80.0;
input int ES_ÜberwachungTimeout = 800;
input double ES_TrailingStop = 370.0;
input bool ES_UseTrailingStop = true;
input double ES_TrailingActivationPips = 0.0;
input bool ES_UseStaleStopLossExit = false;
input int ES_StaleStopLossSeconds = 33800;
input double ES_LotGröße = 0.03;
input int ES_MagicNumber = 12350;
input bool ES_UseSpreadAdjustment = true;
input ENUM_TIMEFRAMES ES_Timeframe = PERIOD_H1;
input bool ES_UseBarData = true;
input int ES_MaxTradesPerCrossover = 9;
input int ES_ProfitCheckBars = 18;
input bool ES_CloseUnprofitableTrades = true;
input bool ES_UseWeeklyADXFilter = true;
input int ES_WeeklyADXPeriod = 15;
input double ES_WeeklyADXMin = 40.0;
input int ES_WeeklyADXBarShift = 2;
input bool ES_WeeklyADXUseDirection = true;
//+------------------------------------------------------------------+
//| Strategy 3: RSICrossOverReversalXAUUSD |
//| PEPPERSTONE US: Gold symbol is typically "XAUUSD" or "GOLD" |
//+------------------------------------------------------------------+
input group "=== RSI CrossOver Reversal Strategy ==="
input string RC_Symbol = "XAU";
input int RC_MagicNumber = 7;
input int RC_rsiPeriod = 19;
input int RC_overboughtLevel = 93;
input int RC_oversoldLevel = 22;
input double RC_entryRSIBuySpread = 0;
input double RC_entryRSISellSpread = 0;
input double RC_lotSize = 0.01;
input int RC_slippage = 3;
input int RC_cooldownSeconds = 209;
input ENUM_TIMEFRAMES RC_TimeFrame1 = PERIOD_M1;
input ENUM_TIMEFRAMES RC_TimeFrame2 = PERIOD_M1;
input ENUM_TIMEFRAMES RC_BarTimeFrame = PERIOD_M12;
input int RC_emaPeriod = 140;
input double RC_emaSlopeThreshold = 105;
input double RC_exitBuyRSI = 86;
input double RC_exitSellRSI = 10;
input double RC_TrailingStop = 295;
input double RC_emaDistanceThreshold = 165;
input bool RC_UseTrendStrengthFilter = true;
input int RC_tradingHourOneBegin = 24;
input int RC_tradingHourOneEnd = 22;
input int RC_tradingHourTwoBegin = 6;
input int RC_tradingHourTwoEnd = 19;
input bool RC_Sunday = false;
input bool RC_Monday = false;
input bool RC_Tuesday = true;
input bool RC_Wednesday = true;
input bool RC_Thursday = true;
input bool RC_Friday = false;
input bool RC_Saturday = false;
//+------------------------------------------------------------------+
//| Strategy 4: RSIMidPointHijackXAUUSD |
//| PEPPERSTONE US: Gold symbol is typically "XAUUSD" or "GOLD" |
//+------------------------------------------------------------------+
input group "=== RSI MidPoint Hijack Strategy ==="
input string RM_Symbol = "XAU";
input ENUM_TIMEFRAMES RM_InpTimeframe = PERIOD_H1;
input double RM_InpLotSize = 0.02;
input int RM_InpMagicNumberRSIFollow = 1001;
input int RM_InpMagicNumberRSIReverse = 1002;
input int RM_InpMagicNumberEMACross = 1003;
input bool RM_InpEnableRSIFollow = true;
input bool RM_InpEnableRSIReverse = true;
input bool RM_InpEnableEMACross = true;
input bool RM_InpEnableStrategyLock = false;
input double RM_InpLockProfitThreshold = 0.0;
input bool RM_InpCloseOppositeTrades = false;
input int RM_InpRSIPeriod = 32;
input int RM_InpRSIOverbought = 78;
input int RM_InpRSIOversold = 46;
input int RM_InpRSIExitLevel = 44;
input int RM_InpRSIFollowStartHour = 23;
input int RM_InpRSIFollowEndHour = 8;
input bool RM_InpRSIFollowCloseOutsideHours = false;
input int RM_InpRSIReversePeriod = 59;
input int RM_InpRSIReverseOverbought = 51;
input int RM_InpRSIReverseOversold = 49;
input int RM_InpRSIReverseCrossLevel = 53;
input int RM_InpRSIReverseExitLevel = 48;
input int RM_InpRSIReverseStartHour = 7;
input int RM_InpRSIReverseEndHour = 13;
input bool RM_InpRSIReverseCloseOutsideHours = false;
input int RM_InpRSIReverseCooldownBars = 15;
input bool RM_InpRSIReverseCooldownOnLoss = true;
input int RM_InpEMAPeriod = 120;
input int RM_InpEMACrossStartHour = 8;
input int RM_InpEMACrossEndHour = 14;
input bool RM_InpEMACrossCloseOutsideHours = true;
input bool RM_InpUseEMADistanceEntry = true;
input double RM_InpEMADistancePips = 160.0;
input int RM_InpEMADistancePeriod = 26;
//+------------------------------------------------------------------+
//| Strategy 5-10: RSI Scalping Strategies |
//| Each RSI Scalping strategy trades on its own symbol: |
//| - APPL: Apple stock (AAPL) |
//| - BTCUSD: Bitcoin/USD |
//| - NVDA: NVIDIA stock |
//| - TSLA: Tesla stock |
//| - XAUUSD: Gold/USD |
//| |
//| PEPPERSTONE US SYMBOL FORMATS: |
//| - Stocks may use: "AAPL.US", "NASDAQ:AAPL", or just "AAPL" |
//| - To find correct symbols: |
//| 1. Open Market Watch (Ctrl+M) |
//| 2. Right-click > Show All |
//| 3. Search for the stock name |
//| 4. Use the exact symbol name shown |
//+------------------------------------------------------------------+
input group "=== RSI Scalping APPL (AAPL) - Pepperstone US ==="
input string RS_APPL_Symbol = "AAPL.NAS"; // Pepperstone / match tester set (also try AAPL.US)
input ENUM_TIMEFRAMES RS_APPL_TimeFrame = PERIOD_M10;
input int RS_APPL_RSI_Period = 14;
input ENUM_APPLIED_PRICE RS_APPL_RSI_Applied_Price = PRICE_CLOSE;
input double RS_APPL_RSI_Overbought = 80;
input double RS_APPL_RSI_Oversold = 78;
input double RS_APPL_RSI_Target_Buy = 94;
input double RS_APPL_RSI_Target_Sell = 44;
input int RS_APPL_BarsToWait = 7;
input double RS_APPL_LotSize = 25;
input int RS_APPL_MagicNumber = 20001;
input int RS_APPL_Slippage = 3;
input group "=== RSI Scalping BTCUSD ==="
input string RS_BTCUSD_Symbol = "BTCUSD"; // Pepperstone may use: "BTCUSD", "BTC/USD", or "BTCUSD.c"
input ENUM_TIMEFRAMES RS_BTCUSD_TimeFrame = PERIOD_H1;
input int RS_BTCUSD_RSI_Period = 14;
input ENUM_APPLIED_PRICE RS_BTCUSD_RSI_Applied_Price = PRICE_CLOSE;
input double RS_BTCUSD_RSI_Overbought = 90;
input double RS_BTCUSD_RSI_Oversold = 73;
input double RS_BTCUSD_RSI_Target_Buy = 88;
input double RS_BTCUSD_RSI_Target_Sell = 48;
input int RS_BTCUSD_BarsToWait = 6;
input double RS_BTCUSD_LotSize = 0.1;
input int RS_BTCUSD_MagicNumber = 123459123;
input int RS_BTCUSD_Slippage = 3;
input group "=== RSI Scalping NVDA - Pepperstone US ==="
input string RS_NVDA_Symbol = "NVDA.NAS"; // Pepperstone / match tester set (also try NVDA.US)
input ENUM_TIMEFRAMES RS_NVDA_TimeFrame = PERIOD_M15;
input int RS_NVDA_RSI_Period = 8;
input ENUM_APPLIED_PRICE RS_NVDA_RSI_Applied_Price = PRICE_CLOSE;
input double RS_NVDA_RSI_Overbought = 36;
input double RS_NVDA_RSI_Oversold = 38;
input double RS_NVDA_RSI_Target_Buy = 90;
input double RS_NVDA_RSI_Target_Sell = 70;
input int RS_NVDA_BarsToWait = 5;
input double RS_NVDA_LotSize = 50;
input int RS_NVDA_MagicNumber = 20003;
input int RS_NVDA_Slippage = 3;
input group "=== RSI Scalping TSLA - Pepperstone US ==="
input string RS_TSLA_Symbol = "TSLA.NAS"; // Pepperstone / match tester set (also try TSLA.US)
input ENUM_TIMEFRAMES RS_TSLA_TimeFrame = PERIOD_H1;
input int RS_TSLA_RSI_Period = 14;
input ENUM_APPLIED_PRICE RS_TSLA_RSI_Applied_Price = PRICE_CLOSE;
input double RS_TSLA_RSI_Overbought = 54;
input double RS_TSLA_RSI_Oversold = 73;
input double RS_TSLA_RSI_Target_Buy = 87;
input double RS_TSLA_RSI_Target_Sell = 33;
input int RS_TSLA_BarsToWait = 1;
input double RS_TSLA_LotSize = 50;
input int RS_TSLA_MagicNumber = 125421321;
input int RS_TSLA_Slippage = 3;
input group "=== RSI Scalping XAUUSD ==="
input string RS_XAUUSD_Symbol = "XAU";
input ENUM_TIMEFRAMES RS_XAUUSD_TimeFrame = PERIOD_H1;
input int RS_XAUUSD_RSI_Period = 14;
input ENUM_APPLIED_PRICE RS_XAUUSD_RSI_Applied_Price = PRICE_CLOSE;
input double RS_XAUUSD_RSI_Overbought = 71;
input double RS_XAUUSD_RSI_Oversold = 57;
input double RS_XAUUSD_RSI_Target_Buy = 80;
input double RS_XAUUSD_RSI_Target_Sell = 57;
input int RS_XAUUSD_BarsToWait = 4;
input double RS_XAUUSD_LotSize = 0.1;
input int RS_XAUUSD_MagicNumber = 129102315;
input int RS_XAUUSD_Slippage = 3;
input group "=== RSI Scalping Reversal Escape (XAUUSD only) ==="
input bool RS_UseReversalEscape = true;
input int RS_ReversalATRPeriod = 14;
input double RS_ReversalAdverseAtrMult = 5.25;
input int RS_ReversalSignsRequired = 2;
input double RS_ReversalRsiVelocity = 16.0;
input double RS_ReversalBodyAtrMult = 5.1;
input group "=== RSI Scalping APPL — Trailing (cluster-fuck BTC-style defaults) ==="
input bool RS_APPL_UseTrailingStop = true;
input double RS_APPL_TrailDistancePoints = 120.0;
input double RS_APPL_TrailActivationPoints = 0.0;
input group "=== RSI Scalping BTCUSD — Trailing ==="
input bool RS_BTCUSD_UseTrailingStop = true;
input double RS_BTCUSD_TrailDistancePoints = 120.0;
input double RS_BTCUSD_TrailActivationPoints = 0.0;
input group "=== RSI Scalping NVDA — Trailing ==="
input bool RS_NVDA_UseTrailingStop = true;
input double RS_NVDA_TrailDistancePoints = 375.0;
input double RS_NVDA_TrailActivationPoints = 75.0;
input group "=== RSI Scalping TSLA — Trailing ==="
input bool RS_TSLA_UseTrailingStop = true;
input double RS_TSLA_TrailDistancePoints = 900.0;
input double RS_TSLA_TrailActivationPoints = 950.0;
input group "=== RSI Scalping XAUUSD — Trailing ==="
input bool RS_XAUUSD_UseTrailingStop = true;
input double RS_XAUUSD_TrailDistancePoints = 1000.0;
input double RS_XAUUSD_TrailActivationPoints = 550.0;
//+------------------------------------------------------------------+
//| Strategy 11-12: RSI Reversal Asian Strategies |
//| Each RSI Reversal Asian strategy trades on its own symbol: |
//| - EURUSD: Euro/USD |
//| - AUDUSD: Australian Dollar/USD |
//+------------------------------------------------------------------+
input group "=== RSI Reversal Asian EURUSD ==="
input string RRA_EURUSD_Symbol = "EURUSD";
input int RRA_EURUSD_RSIPeriod = 28;
input double RRA_EURUSD_OverboughtLevel = 60;
input double RRA_EURUSD_OversoldLevel = 8;
input int RRA_EURUSD_TakeProfitPips = 175;
input int RRA_EURUSD_StopLossPips = 5;
input double RRA_EURUSD_MaxLotSize = 0.1;
input int RRA_EURUSD_MaxSpread = 1000;
input int RRA_EURUSD_MaxDuration = 270;
input bool RRA_EURUSD_UseStopLoss = false;
input bool RRA_EURUSD_UseTakeProfit = false;
input bool RRA_EURUSD_UseRSIExit = true;
input double RRA_EURUSD_RSIExitLevel = 55;
input bool RRA_EURUSD_CloseOutsideSession = false;
input ENUM_TIMEFRAMES RRA_EURUSD_TimeFrame = PERIOD_M15;
input int RRA_EURUSD_MagicNumber = 30001;
input int RRA_EURUSD_Slippage = 3;
input group "=== RSI Reversal Asian AUDUSD ==="
input string RRA_AUDUSD_Symbol = "AUDUSD";
input int RRA_AUDUSD_RSIPeriod = 28;
input double RRA_AUDUSD_OverboughtLevel = 68;
input double RRA_AUDUSD_OversoldLevel = 30;
input int RRA_AUDUSD_TakeProfitPips = 175;
input int RRA_AUDUSD_StopLossPips = 5;
input double RRA_AUDUSD_MaxLotSize = 0.2;
input int RRA_AUDUSD_MaxSpread = 1000;
input int RRA_AUDUSD_MaxDuration = 340;
input bool RRA_AUDUSD_UseStopLoss = false;
input bool RRA_AUDUSD_UseTakeProfit = false;
input bool RRA_AUDUSD_UseRSIExit = true;
input double RRA_AUDUSD_RSIExitLevel = 48;
input bool RRA_AUDUSD_CloseOutsideSession = true;
input ENUM_TIMEFRAMES RRA_AUDUSD_TimeFrame = PERIOD_M15;
input int RRA_AUDUSD_MagicNumber = 30002;
input int RRA_AUDUSD_Slippage = 3;
input group "=== SuperEMA (EMA + CCI + MACD) ==="
input string SE_Symbol = "XAU";
input ENUM_TIMEFRAMES SE_Timeframe = PERIOD_M15;
input double SE_LotSize = 0.01;
input int SE_SlippagePoints = 55;
input int SE_MagicNumber = 940001;
input int SE_EmaFast = 40;
input int SE_EmaMid = 180;
input int SE_EmaSlow = 125;
input int SE_EmaTrendBars = 3;
input int SE_CciPeriod = 17;
input double SE_CciOverbought = 80.0;
input double SE_CciOversold = -140.0;
input int SE_PullbackCciLookback = 20;
input int SE_MacdFast = 14;
input int SE_MacdSlow = 38;
input int SE_MacdSignal = 9;
input ENUM_SE_ENTRY_STYLE SE_EntryStyle = SE_ENTRY_LAMBERT;
input bool SE_OneTradeOnly = true;
input bool SE_UseStructuralSL = false;
input double SE_SlBufferPoints = 110;
input bool SE_ExitOnTrendFlip = false;
input bool SE_ExitOnMacdFlip = false;
input bool SE_ExitOnCciZeroCross = true;
input int SE_MaxHoldingBars = 168;
input bool SE_ExitBelowMidEma = false;
input bool SE_DebugLogs = false;
input group "=== RSI Consolidation (ranging / mean-reversion) ==="
input string RCO_Symbol = "XAU";
input ENUM_TIMEFRAMES RCO_SignalTF = PERIOD_M15;
input bool RCO_EntryOnNewBarOnly = true;
input int RCO_ADX_Period = 23;
input double RCO_ADX_Max = 29.0;
input bool RCO_UseATRRatioFilter = true;
input int RCO_ATR_Period = 8;
input int RCO_ATR_SMA_Period = 35;
input double RCO_ATR_Ratio_Max = 1.36;
input bool RCO_UseFlatEMAFilter = true;
input int RCO_EMA_Fast = 13;
input int RCO_EMA_Slow = 17;
input double RCO_EMA_Separation_MaxPct = 0.26;
input int RCO_RSI_Period = 8;
input ENUM_APPLIED_PRICE RCO_RSI_Price = PRICE_OPEN;
input double RCO_RSI_Oversold = 22.0;
input double RCO_RSI_Overbought = 63.0;
input bool RCO_UseRSI_MeanExit = true;
input double RCO_RSI_Exit_Long = 48.0;
input double RCO_RSI_Exit_Short = 52.0;
input double RCO_SL_ATR_Mult = 2.15;
input double RCO_TP_ATR_Mult = 2.40;
input int RCO_MaxBarsInTrade = 54;
input double RCO_Lots = 0.10;
input ulong RCO_MagicNumber = 20250420;
input int RCO_Slippage = 10;
input int RCO_MaxSpreadPoints = 28;
input group "=== SimpleTrendline BTCUSD ==="
input string ST_BTC_Symbol = "BTCUSD";
input ENUM_TIMEFRAMES ST_BTC_SignalTF = PERIOD_H1;
input ENUM_TIMEFRAMES ST_BTC_HigherTF = PERIOD_H4;
input int ST_BTC_MAPeriod = 150;
input ENUM_MA_METHOD ST_BTC_MAMethod = MODE_SMMA;
input ENUM_APPLIED_PRICE ST_BTC_AppliedPrice = PRICE_OPEN;
input int ST_BTC_HTFBarsToScan = 1200;
input double ST_BTC_LineTouchTolerance = 170.0;
input double ST_BTC_BreakBuffer = 90.0;
input ulong ST_BTC_MagicNumber = 26042501;
input bool ST_BTC_DrawTrendline = true;
input group "=== SimpleTrendline XAUUSD ==="
input string ST_XAU_Symbol = "XAU";
input ENUM_TIMEFRAMES ST_XAU_SignalTF = PERIOD_H1;
input ENUM_TIMEFRAMES ST_XAU_HigherTF = PERIOD_M10;
input int ST_XAU_MAPeriod = 65;
input ENUM_MA_METHOD ST_XAU_MAMethod = MODE_EMA;
input ENUM_APPLIED_PRICE ST_XAU_AppliedPrice = PRICE_OPEN;
input int ST_XAU_HTFBarsToScan = 500;
input double ST_XAU_LineTouchTolerance = 220.0;
input double ST_XAU_BreakBuffer = 110.0;
input ulong ST_XAU_MagicNumber = 26042503;
input bool ST_XAU_DrawTrendline = true;
input group "=== RSI Secret Sauce XAUUSD ==="
input string RSS_Symbol = "XAU";
input int RSS_MagicNumber = 789012;
input int RSS_Slippage = 10;
input ENUM_TIMEFRAMES RSS_Timeframe = PERIOD_M30;
input int RSS_RSIPeriod = 16;
input double RSS_RSIOverbought = 72.5;
input double RSS_RSIOversold = 32.5;
input int RSS_RSILookback = 60;
input int RSS_PeakBars = 2;
input double RSS_StopLossATR = 2.75;
input double RSS_TakeProfitATR = 5.0;
input int RSS_ATRPeriod = 14;
input bool RSS_UseSwingStopLoss = false;
input int RSS_SwingLookback = 30;
input int RSS_MaxPositions = 1;
input int RSS_MinBarsBetweenTrades = 7;
//+------------------------------------------------------------------+
//| Balance scaling: LOT_* = nominal size at ORCH_ReferenceBalance |
//+------------------------------------------------------------------+
double United_BalanceScaleFactor()
{
if(!ORCH_ScaleLotsByBalance || ORCH_ReferenceBalance <= 0.0)
return 1.0;
const double money = ORCH_UseEquityInsteadOfBalance
? AccountInfoDouble(ACCOUNT_EQUITY)
: AccountInfoDouble(ACCOUNT_BALANCE);
double raw = money / ORCH_ReferenceBalance;
if(raw < ORCH_MinBalanceScale)
raw = ORCH_MinBalanceScale;
if(raw > ORCH_MaxBalanceScale)
raw = ORCH_MaxBalanceScale;
return raw;
}
double United_ScaledLot(const double baseLot)
{
const double lot = baseLot * United_BalanceScaleFactor();
return (lot > 0.0 ? lot : 0.0);
}
void United_RefreshScaledLots()
{
g_DB_LotSize = United_ScaledLot(LOT_DB_DarvasBox);
g_ES_LotSize = United_ScaledLot(LOT_ES_EMASlopeDistance);
g_RC_LotSize = United_ScaledLot(LOT_RC_RSICrossOver);
g_RM_LotSize = United_ScaledLot(LOT_RM_RSIMidPointHijack);
g_Pos_RS_APPL = United_ScaledLot(LOT_RS_APPL);
g_Pos_RS_BTCUSD = United_ScaledLot(LOT_RS_BTCUSD);
g_Pos_RS_NVDA = United_ScaledLot(LOT_RS_NVDA);
g_Pos_RS_TSLA = United_ScaledLot(LOT_RS_TSLA);
g_Pos_RS_XAUUSD = United_ScaledLot(LOT_RS_XAUUSD);
g_Pos_RRA_EURUSD = United_ScaledLot(LOT_RRA_EURUSD);
g_Pos_RRA_AUDUSD = United_ScaledLot(LOT_RRA_AUDUSD);
g_Pos_SE = United_ScaledLot(LOT_SE_SuperEMA);
g_Pos_RCO = United_ScaledLot(LOT_RCO_RSIConsolidation);
g_Pos_ST_BTCUSD = United_ScaledLot(LOT_ST_BTCUSD);
g_Pos_ST_XAUUSD = United_ScaledLot(LOT_ST_XAUUSD);
g_RSS_LotSize = United_ScaledLot(LOT_RSS_SecretSauce);
}
//+------------------------------------------------------------------+
//| Global Variables - DarvasBox |
//+------------------------------------------------------------------+
struct DarvasBoxData {
string symbol;
bool isInitialized;
double boxHigh;
double boxLow;
bool boxFormed;
datetime lastBoxTime;
string boxName;
double minStopLevel;
double point;
CTrade trade;
int maHandle;
int volumeHandle;
datetime lastBarTime;
};
//+------------------------------------------------------------------+
//| Global Variables - EMA Slope Distance |
//+------------------------------------------------------------------+
struct EMASlopeData {
string symbol;
bool isInitialized;
int ema_handle;
double ema_array[];
datetime letzte_überwachung_zeit;
bool überwachung_aktiv;
bool preis_trigger_aktiv;
bool steigung_trigger_aktiv;
int ticket;
CTrade trade;
int trades_in_current_crossover;
bool crossover_detected;
datetime trade_open_time;
datetime last_bar_time;
datetime es_last_sl_adjust_success_time;
};
//+------------------------------------------------------------------+
//| Global Variables - RSI CrossOver Reversal |
//+------------------------------------------------------------------+
struct RSICrossOverData {
string symbol;
bool isInitialized;
int rsiHandle;
int emaHandle;
double previousRSIDef;
CTrade trade;
datetime lastTradeTime;
datetime bartime;
bool WeekDays[7];
datetime lastBarTime;
};
//+------------------------------------------------------------------+
//| Global Variables - RSI MidPoint Hijack |
//+------------------------------------------------------------------+
struct RSIMidPointData {
string symbol;
bool isInitialized;
int rsiHandle;
int rsiReverseHandle;
int emaHandle;
bool rsiOverbought;
bool rsiOversold;
bool rsiReverseOverbought;
bool rsiReverseOversold;
CTrade trade;
CPositionInfo positionInfo;
bool emaCrossBuySignal;
bool emaCrossSellSignal;
int emaCrossSignalBar;
datetime lastBarTime;
datetime rsiReverseLastCloseTime;
bool rsiReverseInCooldown;
double lastBarRSI;
double lastBarRSIReverse;
double lastBarEMA;
double lastBarClose;
double lastBarEMAPrev;
double lastBarClosePrev;
};
//+------------------------------------------------------------------+
//| Global Strategy Instances |
//+------------------------------------------------------------------+
DarvasBoxData dbData;
EMASlopeData esData;
RSICrossOverData rcData;
RSIMidPointData rmData;
RSIScalpingData rsAPPLData;
RSIScalpingData rsBTCUSDData;
RSIScalpingData rsNVDAData;
RSIScalpingData rsTSLAData;
RSIScalpingData rsXAUUSDData;
SuperEMAData seData;
RSIConsolidationData rcoData;
SimpleTrendlineData stBTCData;
SimpleTrendlineData stXAUData;
RSISecretSauceOrcData rssData;
//+------------------------------------------------------------------+
//| Global Variables - RSI Reversal Asian |
//+------------------------------------------------------------------+
RSIReversalAsianData rraEURUSDData;
RSIReversalAsianData rraAUDUSDData;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
int initResult = INIT_SUCCEEDED;
United_RefreshScaledLots();
// Initialize strategies - log warnings but don't fail entire EA if symbol unavailable
if(EnableDarvasBox)
if(!InitDarvasBox(DB_Symbol))
Print("Warning: DarvasBox strategy failed to initialize for symbol '", DB_Symbol, "'");
if(EnableEMASlopeDistance)
if(!InitEMASlopeDistance(ES_Symbol))
Print("Warning: EMASlopeDistance strategy failed to initialize for symbol '", ES_Symbol, "'");
if(EnableRSICrossOverReversal)
if(!InitRSICrossOverReversal(RC_Symbol))
Print("Warning: RSICrossOverReversal strategy failed to initialize for symbol '", RC_Symbol, "'");
if(EnableRSIMidPointHijack)
if(!InitRSIMidPointHijack(RM_Symbol))
Print("Warning: RSIMidPointHijack strategy failed to initialize for symbol '", RM_Symbol, "'");
// Initialize RSI Scalping strategies - don't fail entire EA if symbol unavailable
if(EnableRSIScalpingAPPL)
InitRSIScalping(rsAPPLData, RS_APPL_Symbol, RS_APPL_TimeFrame, RS_APPL_RSI_Period, RS_APPL_RSI_Applied_Price, RS_APPL_MagicNumber, RS_APPL_Slippage);
if(EnableRSIScalpingBTCUSD)
InitRSIScalping(rsBTCUSDData, RS_BTCUSD_Symbol, RS_BTCUSD_TimeFrame, RS_BTCUSD_RSI_Period, RS_BTCUSD_RSI_Applied_Price, RS_BTCUSD_MagicNumber, RS_BTCUSD_Slippage);
if(EnableRSIScalpingNVDA)
InitRSIScalping(rsNVDAData, RS_NVDA_Symbol, RS_NVDA_TimeFrame, RS_NVDA_RSI_Period, RS_NVDA_RSI_Applied_Price, RS_NVDA_MagicNumber, RS_NVDA_Slippage);
if(EnableRSIScalpingTSLA)
InitRSIScalping(rsTSLAData, RS_TSLA_Symbol, RS_TSLA_TimeFrame, RS_TSLA_RSI_Period, RS_TSLA_RSI_Applied_Price, RS_TSLA_MagicNumber, RS_TSLA_Slippage);
if(EnableRSIScalpingXAUUSD)
InitRSIScalping(rsXAUUSDData, RS_XAUUSD_Symbol, RS_XAUUSD_TimeFrame, RS_XAUUSD_RSI_Period, RS_XAUUSD_RSI_Applied_Price, RS_XAUUSD_MagicNumber, RS_XAUUSD_Slippage);
if(EnableRSISecretSauce)
if(!InitRSISecretSauce(rssData, RSS_Symbol))
Print("Warning: RSI Secret Sauce failed to initialize for symbol '", RSS_Symbol, "'");
if(EnableSuperEMA)
if(!InitSuperEMA(seData, SE_Symbol, SE_Timeframe, SE_SlippagePoints, SE_MagicNumber,
SE_EmaFast, SE_EmaMid, SE_EmaSlow, SE_EmaTrendBars,
SE_CciPeriod, SE_CciOverbought, SE_CciOversold, SE_PullbackCciLookback,
SE_MacdFast, SE_MacdSlow, SE_MacdSignal,
SE_EntryStyle, SE_OneTradeOnly, SE_UseStructuralSL, SE_SlBufferPoints,
SE_ExitOnTrendFlip, SE_ExitOnMacdFlip, SE_ExitOnCciZeroCross,
SE_MaxHoldingBars, SE_ExitBelowMidEma, SE_DebugLogs))
Print("Warning: SuperEMA failed to initialize for symbol '", SE_Symbol, "'");
if(EnableRSIConsolidation)
if(!InitRSIConsolidation(rcoData, RCO_Symbol, RCO_SignalTF, RCO_EntryOnNewBarOnly,
RCO_ADX_Period, RCO_ADX_Max, RCO_UseATRRatioFilter, RCO_ATR_Period, RCO_ATR_SMA_Period, RCO_ATR_Ratio_Max,
RCO_UseFlatEMAFilter, RCO_EMA_Fast, RCO_EMA_Slow, RCO_EMA_Separation_MaxPct,
RCO_RSI_Period, RCO_RSI_Price, RCO_RSI_Oversold, RCO_RSI_Overbought,
RCO_UseRSI_MeanExit, RCO_RSI_Exit_Long, RCO_RSI_Exit_Short, RCO_SL_ATR_Mult, RCO_TP_ATR_Mult,
RCO_MaxBarsInTrade, RCO_MagicNumber, RCO_Slippage, RCO_MaxSpreadPoints))
Print("Warning: RSIConsolidation failed to initialize for symbol '", RCO_Symbol, "'");
// Initialize RSI Reversal Asian strategies
if(EnableRSIReversalAsianEURUSD)
if(!InitRSIReversalAsian(rraEURUSDData, RRA_EURUSD_Symbol, RRA_EURUSD_RSIPeriod, RRA_EURUSD_OverboughtLevel, RRA_EURUSD_OversoldLevel,
RRA_EURUSD_TakeProfitPips, RRA_EURUSD_StopLossPips, LOT_RRA_EURUSD,
RRA_EURUSD_MaxSpread, RRA_EURUSD_MaxDuration, RRA_EURUSD_UseStopLoss,
RRA_EURUSD_UseTakeProfit, RRA_EURUSD_UseRSIExit, RRA_EURUSD_RSIExitLevel,
RRA_EURUSD_CloseOutsideSession, RRA_EURUSD_TimeFrame, RRA_EURUSD_MagicNumber, RRA_EURUSD_Slippage))
Print("Warning: RSIReversalAsianEURUSD strategy failed to initialize for symbol '", RRA_EURUSD_Symbol, "'");
if(EnableRSIReversalAsianAUDUSD)
if(!InitRSIReversalAsian(rraAUDUSDData, RRA_AUDUSD_Symbol, RRA_AUDUSD_RSIPeriod, RRA_AUDUSD_OverboughtLevel, RRA_AUDUSD_OversoldLevel,
RRA_AUDUSD_TakeProfitPips, RRA_AUDUSD_StopLossPips, LOT_RRA_AUDUSD,
RRA_AUDUSD_MaxSpread, RRA_AUDUSD_MaxDuration, RRA_AUDUSD_UseStopLoss,
RRA_AUDUSD_UseTakeProfit, RRA_AUDUSD_UseRSIExit, RRA_AUDUSD_RSIExitLevel,
RRA_AUDUSD_CloseOutsideSession, RRA_AUDUSD_TimeFrame, RRA_AUDUSD_MagicNumber, RRA_AUDUSD_Slippage))
Print("Warning: RSIReversalAsianAUDUSD strategy failed to initialize for symbol '", RRA_AUDUSD_Symbol, "'");
if(EnableSimpleTrendlineBTCUSD)
if(!InitSimpleTrendline(stBTCData, ST_BTC_Symbol, ST_BTC_SignalTF, ST_BTC_HigherTF, ST_BTC_MAPeriod,
ST_BTC_MAMethod, ST_BTC_AppliedPrice, ST_BTC_HTFBarsToScan,
ST_BTC_LineTouchTolerance, ST_BTC_BreakBuffer, ST_BTC_MagicNumber, ST_BTC_DrawTrendline))
Print("Warning: SimpleTrendlineBTCUSD failed to initialize for symbol '", ST_BTC_Symbol, "'");
if(EnableSimpleTrendlineXAUUSD)
if(!InitSimpleTrendline(stXAUData, ST_XAU_Symbol, ST_XAU_SignalTF, ST_XAU_HigherTF, ST_XAU_MAPeriod,
ST_XAU_MAMethod, ST_XAU_AppliedPrice, ST_XAU_HTFBarsToScan,
ST_XAU_LineTouchTolerance, ST_XAU_BreakBuffer, ST_XAU_MagicNumber, ST_XAU_DrawTrendline))
Print("Warning: SimpleTrendlineXAUUSD failed to initialize for symbol '", ST_XAU_Symbol, "'");
Print("United EA initialized. Active strategies: ",
(EnableDarvasBox ? "DarvasBox " : ""),
(EnableEMASlopeDistance ? "EMASlope " : ""),
(EnableRSICrossOverReversal ? "RSICrossOver " : ""),
(EnableRSIMidPointHijack ? "RSIMidPoint " : ""),
(EnableRSIScalpingAPPL ? "RSIScalpingAPPL " : ""),
(EnableRSIScalpingBTCUSD ? "RSIScalpingBTCUSD " : ""),
(EnableRSIScalpingNVDA ? "RSIScalpingNVDA " : ""),
(EnableRSIScalpingTSLA ? "RSIScalpingTSLA " : ""),
(EnableRSIScalpingXAUUSD ? "RSIScalpingXAUUSD " : ""),
(EnableRSISecretSauce ? "RSISecretSauce " : ""),
(EnableSuperEMA ? "SuperEMA " : ""),
(EnableRSIConsolidation ? "RSIConsolidation " : ""),
(EnableRSIReversalAsianEURUSD ? "RSIReversalAsianEURUSD " : ""),
(EnableRSIReversalAsianAUDUSD ? "RSIReversalAsianAUDUSD " : ""),
(EnableSimpleTrendlineBTCUSD ? "SimpleTrendlineBTCUSD " : ""),
(EnableSimpleTrendlineXAUUSD ? "SimpleTrendlineXAUUSD " : ""));
return initResult;
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if(EnableDarvasBox)
DeinitDarvasBox();
if(EnableEMASlopeDistance)
DeinitEMASlopeDistance();
if(EnableRSICrossOverReversal)
DeinitRSICrossOverReversal();
if(EnableRSIMidPointHijack)
DeinitRSIMidPointHijack();
if(EnableRSIScalpingAPPL)
DeinitRSIScalping(rsAPPLData);
if(EnableRSIScalpingBTCUSD)
DeinitRSIScalping(rsBTCUSDData);
if(EnableRSIScalpingNVDA)
DeinitRSIScalping(rsNVDAData);
if(EnableRSIScalpingTSLA)
DeinitRSIScalping(rsTSLAData);
if(EnableRSIScalpingXAUUSD)
DeinitRSIScalping(rsXAUUSDData);
if(EnableRSISecretSauce)
DeinitRSISecretSauce(rssData);
if(EnableSuperEMA)
DeinitSuperEMA(seData);
if(EnableRSIConsolidation)
DeinitRSIConsolidation(rcoData);
if(EnableRSIReversalAsianEURUSD)
DeinitRSIReversalAsian(rraEURUSDData);
if(EnableRSIReversalAsianAUDUSD)
DeinitRSIReversalAsian(rraAUDUSDData);
if(EnableSimpleTrendlineBTCUSD)
DeinitSimpleTrendline(stBTCData);
if(EnableSimpleTrendlineXAUUSD)
DeinitSimpleTrendline(stXAUData);
Print("United EA deinitialized. Reason: ", reason);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
United_RefreshScaledLots();
if(EnableDarvasBox)
ProcessDarvasBox(DB_Symbol);
if(EnableEMASlopeDistance)
ProcessEMASlopeDistance(ES_Symbol);
if(EnableRSICrossOverReversal)
ProcessRSICrossOverReversal(RC_Symbol);
if(EnableRSIMidPointHijack)
ProcessRSIMidPointHijack(RM_Symbol);
if(EnableRSIScalpingAPPL)
ProcessRSIScalping(rsAPPLData, RS_APPL_Symbol, RS_APPL_TimeFrame, RS_APPL_RSI_Period, RS_APPL_RSI_Applied_Price,
RS_APPL_RSI_Overbought, RS_APPL_RSI_Oversold, RS_APPL_RSI_Target_Buy, RS_APPL_RSI_Target_Sell,
RS_APPL_BarsToWait, g_Pos_RS_APPL, RS_APPL_MagicNumber,
false, RS_ReversalATRPeriod, RS_ReversalAdverseAtrMult, RS_ReversalSignsRequired,
RS_ReversalRsiVelocity, RS_ReversalBodyAtrMult,
RS_APPL_UseTrailingStop, RS_APPL_TrailDistancePoints, RS_APPL_TrailActivationPoints);
if(EnableRSIScalpingBTCUSD)
ProcessRSIScalping(rsBTCUSDData, RS_BTCUSD_Symbol, RS_BTCUSD_TimeFrame, RS_BTCUSD_RSI_Period, RS_BTCUSD_RSI_Applied_Price,
RS_BTCUSD_RSI_Overbought, RS_BTCUSD_RSI_Oversold, RS_BTCUSD_RSI_Target_Buy, RS_BTCUSD_RSI_Target_Sell,
RS_BTCUSD_BarsToWait, g_Pos_RS_BTCUSD, RS_BTCUSD_MagicNumber,
false, RS_ReversalATRPeriod, RS_ReversalAdverseAtrMult, RS_ReversalSignsRequired,
RS_ReversalRsiVelocity, RS_ReversalBodyAtrMult,
RS_BTCUSD_UseTrailingStop, RS_BTCUSD_TrailDistancePoints, RS_BTCUSD_TrailActivationPoints);
if(EnableRSIScalpingNVDA)
ProcessRSIScalping(rsNVDAData, RS_NVDA_Symbol, RS_NVDA_TimeFrame, RS_NVDA_RSI_Period, RS_NVDA_RSI_Applied_Price,
RS_NVDA_RSI_Overbought, RS_NVDA_RSI_Oversold, RS_NVDA_RSI_Target_Buy, RS_NVDA_RSI_Target_Sell,
RS_NVDA_BarsToWait, g_Pos_RS_NVDA, RS_NVDA_MagicNumber,
false, RS_ReversalATRPeriod, RS_ReversalAdverseAtrMult, RS_ReversalSignsRequired,
RS_ReversalRsiVelocity, RS_ReversalBodyAtrMult,
RS_NVDA_UseTrailingStop, RS_NVDA_TrailDistancePoints, RS_NVDA_TrailActivationPoints);
if(EnableRSIScalpingTSLA)
ProcessRSIScalping(rsTSLAData, RS_TSLA_Symbol, RS_TSLA_TimeFrame, RS_TSLA_RSI_Period, RS_TSLA_RSI_Applied_Price,
RS_TSLA_RSI_Overbought, RS_TSLA_RSI_Oversold, RS_TSLA_RSI_Target_Buy, RS_TSLA_RSI_Target_Sell,
RS_TSLA_BarsToWait, g_Pos_RS_TSLA, RS_TSLA_MagicNumber,
false, RS_ReversalATRPeriod, RS_ReversalAdverseAtrMult, RS_ReversalSignsRequired,
RS_ReversalRsiVelocity, RS_ReversalBodyAtrMult,
RS_TSLA_UseTrailingStop, RS_TSLA_TrailDistancePoints, RS_TSLA_TrailActivationPoints);
if(EnableRSIScalpingXAUUSD)
ProcessRSIScalping(rsXAUUSDData, RS_XAUUSD_Symbol, RS_XAUUSD_TimeFrame, RS_XAUUSD_RSI_Period, RS_XAUUSD_RSI_Applied_Price,
RS_XAUUSD_RSI_Overbought, RS_XAUUSD_RSI_Oversold, RS_XAUUSD_RSI_Target_Buy, RS_XAUUSD_RSI_Target_Sell,
RS_XAUUSD_BarsToWait, g_Pos_RS_XAUUSD, RS_XAUUSD_MagicNumber,
RS_UseReversalEscape, RS_ReversalATRPeriod, RS_ReversalAdverseAtrMult, RS_ReversalSignsRequired,
RS_ReversalRsiVelocity, RS_ReversalBodyAtrMult,
RS_XAUUSD_UseTrailingStop, RS_XAUUSD_TrailDistancePoints, RS_XAUUSD_TrailActivationPoints);
if(EnableRSISecretSauce)
ProcessRSISecretSauce(rssData, g_RSS_LotSize);
if(EnableRSIReversalAsianEURUSD)
ProcessRSIReversalAsian(rraEURUSDData, g_Pos_RRA_EURUSD);
if(EnableRSIReversalAsianAUDUSD)
ProcessRSIReversalAsian(rraAUDUSDData, g_Pos_RRA_AUDUSD);
if(EnableSuperEMA)
ProcessSuperEMA(seData, g_Pos_SE);
if(EnableRSIConsolidation)
ProcessRSIConsolidation(rcoData, g_Pos_RCO);
if(EnableSimpleTrendlineBTCUSD)
ProcessSimpleTrendline(stBTCData, g_Pos_ST_BTCUSD);
if(EnableSimpleTrendlineXAUUSD)
ProcessSimpleTrendline(stXAUData, g_Pos_ST_XAUUSD);
}
//+------------------------------------------------------------------+
Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

-613
View File
@@ -1,613 +0,0 @@
//+------------------------------------------------------------------+
//| 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 strict
#include <Trade\Trade.mqh>
#include <Trade\PositionInfo.mqh>
#include <Indicators\Trend.mqh>
#include <Indicators\Volumes.mqh>
#include "MagicNumberHelpers.mqh"
//+------------------------------------------------------------------+
//| Strategy Enable/Disable Switches |
//+------------------------------------------------------------------+
input group "=== Strategy Enable/Disable ==="
input bool EnableDarvasBox = true;
input bool EnableEMASlopeDistance = true;
input bool EnableRSICrossOverReversal = true;
input bool EnableRSIMidPointHijack = true;
input bool EnableRSIScalpingAPPL = true;
input bool EnableRSIScalpingBTCUSD = true;
input bool EnableRSIScalpingMSFT = true;
input bool EnableRSIScalpingNVDA = true;
input bool EnableRSIScalpingTSLA = true;
input bool EnableRSIScalpingXAUUSD = true;
//+------------------------------------------------------------------+
//| Strategy 1: DarvasBoxXAUUSD |
//+------------------------------------------------------------------+
input group "=== DarvasBox Strategy ==="
input string DB_Symbol = "XAUUSD";
input int DB_BoxPeriod = 165;
input double DB_BoxDeviation = 30000; // Increased to allow larger ranges (was 25140)
input int DB_VolumeThreshold = 0; // Set to 0 to disable volume threshold check. Volume data from indicator used instead.
input double DB_StopLoss = 1665;
input double DB_TakeProfit = 3685;
input bool DB_EnableLogging = false;
input color DB_BoxColor = clrBlue;
input int DB_BoxWidth = 1;
input ENUM_TIMEFRAMES DB_TrendTimeframe = PERIOD_H2;
input int DB_MA_Period = 125;
input ENUM_MA_METHOD DB_MA_Method = MODE_EMA;
input ENUM_APPLIED_PRICE DB_MA_Price = PRICE_WEIGHTED;
input double DB_TrendThreshold = 4.94;
input int DB_VolumeMA_Period = 110;
input double DB_VolumeThresholdMultiplier = 1.5;
input int DB_MagicNumber = 135790;
//+------------------------------------------------------------------+
//| Strategy 2: EMASlopeDistanceCocktailXAUUSD |
//| PEPPERSTONE US: Gold symbol is typically "XAUUSD" or "GOLD" |
//+------------------------------------------------------------------+
input group "=== EMA Slope Distance Strategy ==="
input string ES_Symbol = "XAUUSD";
input int ES_EMA_Periode = 46;
input double ES_PreisSchwelle = 600.0;
input double ES_SteigungSchwelle = 80.0;
input int ES_ÜberwachungTimeout = 800;
input double ES_TrailingStop = 370.0;
input bool ES_UseTrailingStop = true;
input double ES_TrailingActivationPips = 0.0;
input bool ES_UseStaleStopLossExit = false;
input int ES_StaleStopLossSeconds = 33800;
input double ES_LotGröße = 0.03;
input int ES_MagicNumber = 12350;
input bool ES_UseSpreadAdjustment = true;
input ENUM_TIMEFRAMES ES_Timeframe = PERIOD_H1;
input bool ES_UseBarData = true;
input int ES_MaxTradesPerCrossover = 9;
input int ES_ProfitCheckBars = 18;
input bool ES_CloseUnprofitableTrades = true;
input bool ES_UseWeeklyADXFilter = true;
input int ES_WeeklyADXPeriod = 15;
input double ES_WeeklyADXMin = 40.0;
input int ES_WeeklyADXBarShift = 2;
input bool ES_WeeklyADXUseDirection = true;
//+------------------------------------------------------------------+
//| Strategy 3: RSICrossOverReversalXAUUSD |
//| PEPPERSTONE US: Gold symbol is typically "XAUUSD" or "GOLD" |
//+------------------------------------------------------------------+
input group "=== RSI CrossOver Reversal Strategy ==="
input string RC_Symbol = "XAUUSD";
input int RC_MagicNumber = 7;
input int RC_rsiPeriod = 19;
input int RC_overboughtLevel = 93;
input int RC_oversoldLevel = 22;
input double RC_entryRSIBuySpread = 0;
input double RC_entryRSISellSpread = 0;
input double RC_lotSize = 0.01;
input int RC_slippage = 3;
input int RC_cooldownSeconds = 209;
input ENUM_TIMEFRAMES RC_TimeFrame1 = PERIOD_M1;
input ENUM_TIMEFRAMES RC_TimeFrame2 = PERIOD_M1;
input ENUM_TIMEFRAMES RC_BarTimeFrame = PERIOD_M12;
input int RC_emaPeriod = 140;
input double RC_emaSlopeThreshold = 105;
input double RC_exitBuyRSI = 86;
input double RC_exitSellRSI = 10;
input double RC_TrailingStop = 295;
input double RC_emaDistanceThreshold = 165;
input int RC_tradingHourOneBegin = 24;
input int RC_tradingHourOneEnd = 22;
input int RC_tradingHourTwoBegin = 6;
input int RC_tradingHourTwoEnd = 19;
input bool RC_Sunday = false;
input bool RC_Monday = false;
input bool RC_Tuesday = true;
input bool RC_Wednesday = true;
input bool RC_Thursday = true;
input bool RC_Friday = false;
input bool RC_Saturday = false;
//+------------------------------------------------------------------+
//| Strategy 4: RSIMidPointHijackXAUUSD |
//| PEPPERSTONE US: Gold symbol is typically "XAUUSD" or "GOLD" |
//+------------------------------------------------------------------+
input group "=== RSI MidPoint Hijack Strategy ==="
input string RM_Symbol = "XAUUSD";
input ENUM_TIMEFRAMES RM_InpTimeframe = PERIOD_H1;
input double RM_InpLotSize = 0.02;
input int RM_InpMagicNumberRSIFollow = 1001;
input int RM_InpMagicNumberRSIReverse = 1002;
input int RM_InpMagicNumberEMACross = 1003;
input bool RM_InpEnableRSIFollow = true;
input bool RM_InpEnableRSIReverse = true;
input bool RM_InpEnableEMACross = true;
input bool RM_InpEnableStrategyLock = false;
input double RM_InpLockProfitThreshold = 0.0;
input bool RM_InpCloseOppositeTrades = false;
input int RM_InpRSIPeriod = 32;
input int RM_InpRSIOverbought = 78;
input int RM_InpRSIOversold = 46;
input int RM_InpRSIExitLevel = 44;
input int RM_InpRSIFollowStartHour = 23;
input int RM_InpRSIFollowEndHour = 8;
input bool RM_InpRSIFollowCloseOutsideHours = false;
input int RM_InpRSIReversePeriod = 59;
input int RM_InpRSIReverseOverbought = 51;
input int RM_InpRSIReverseOversold = 49;
input int RM_InpRSIReverseCrossLevel = 53;
input int RM_InpRSIReverseExitLevel = 48;
input int RM_InpRSIReverseStartHour = 7;
input int RM_InpRSIReverseEndHour = 13;
input bool RM_InpRSIReverseCloseOutsideHours = false;
input int RM_InpRSIReverseCooldownBars = 15;
input bool RM_InpRSIReverseCooldownOnLoss = true;
input int RM_InpEMAPeriod = 120;
input int RM_InpEMACrossStartHour = 8;
input int RM_InpEMACrossEndHour = 14;
input bool RM_InpEMACrossCloseOutsideHours = true;
input bool RM_InpUseEMADistanceEntry = true;
input double RM_InpEMADistancePips = 160.0;
input int RM_InpEMADistancePeriod = 26;
//+------------------------------------------------------------------+
//| Strategy 5-10: RSI Scalping Strategies |
//| Each RSI Scalping strategy trades on its own symbol: |
//| - APPL: Apple stock (AAPL) |
//| - BTCUSD: Bitcoin/USD |
//| - MSFT: Microsoft stock |
//| - NVDA: NVIDIA stock |
//| - TSLA: Tesla stock |
//| - XAUUSD: Gold/USD |
//| |
//| PEPPERSTONE US SYMBOL FORMATS: |
//| - Stocks may use: "AAPL.US", "NASDAQ:AAPL", or just "AAPL" |
//| - To find correct symbols: |
//| 1. Open Market Watch (Ctrl+M) |
//| 2. Right-click > Show All |
//| 3. Search for the stock name |
//| 4. Use the exact symbol name shown |
//+------------------------------------------------------------------+
input group "=== RSI Scalping APPL (AAPL) - Pepperstone US ==="
input string RS_APPL_Symbol = "AAPL.US"; // Try: "AAPL.US", "NASDAQ:AAPL", or "AAPL"
input ENUM_TIMEFRAMES RS_APPL_TimeFrame = PERIOD_M10;
input int RS_APPL_RSI_Period = 14;
input ENUM_APPLIED_PRICE RS_APPL_RSI_Applied_Price = PRICE_CLOSE;
input double RS_APPL_RSI_Overbought = 80;
input double RS_APPL_RSI_Oversold = 78;
input double RS_APPL_RSI_Target_Buy = 94;
input double RS_APPL_RSI_Target_Sell = 44;
input int RS_APPL_BarsToWait = 7;
input double RS_APPL_LotSize = 25;
input int RS_APPL_MagicNumber = 20001;
input int RS_APPL_Slippage = 3;
input group "=== RSI Scalping BTCUSD ==="
input string RS_BTCUSD_Symbol = "BTCUSD"; // Pepperstone may use: "BTCUSD", "BTC/USD", or "BTCUSD.c"
input ENUM_TIMEFRAMES RS_BTCUSD_TimeFrame = PERIOD_H1;
input int RS_BTCUSD_RSI_Period = 14;
input ENUM_APPLIED_PRICE RS_BTCUSD_RSI_Applied_Price = PRICE_CLOSE;
input double RS_BTCUSD_RSI_Overbought = 90;
input double RS_BTCUSD_RSI_Oversold = 73;
input double RS_BTCUSD_RSI_Target_Buy = 88;
input double RS_BTCUSD_RSI_Target_Sell = 48;
input int RS_BTCUSD_BarsToWait = 6;
input double RS_BTCUSD_LotSize = 0.1;
input int RS_BTCUSD_MagicNumber = 123459123;
input int RS_BTCUSD_Slippage = 3;
input group "=== RSI Scalping MSFT - Pepperstone US ==="
input string RS_MSFT_Symbol = "MSFT.US"; // Try: "MSFT.US", "NASDAQ:MSFT", or "MSFT"
input ENUM_TIMEFRAMES RS_MSFT_TimeFrame = PERIOD_H3;
input int RS_MSFT_RSI_Period = 14;
input ENUM_APPLIED_PRICE RS_MSFT_RSI_Applied_Price = PRICE_CLOSE;
input double RS_MSFT_RSI_Overbought = 19;
input double RS_MSFT_RSI_Oversold = 50;
input double RS_MSFT_RSI_Target_Buy = 71;
input double RS_MSFT_RSI_Target_Sell = 70;
input int RS_MSFT_BarsToWait = 1;
input double RS_MSFT_LotSize = 50;
input int RS_MSFT_MagicNumber = 20002;
input int RS_MSFT_Slippage = 3;
input group "=== RSI Scalping NVDA - Pepperstone US ==="
input string RS_NVDA_Symbol = "NVDA.US"; // Try: "NVDA.US", "NASDAQ:NVDA", or "NVDA"
input ENUM_TIMEFRAMES RS_NVDA_TimeFrame = PERIOD_M15;
input int RS_NVDA_RSI_Period = 8;
input ENUM_APPLIED_PRICE RS_NVDA_RSI_Applied_Price = PRICE_CLOSE;
input double RS_NVDA_RSI_Overbought = 36;
input double RS_NVDA_RSI_Oversold = 38;
input double RS_NVDA_RSI_Target_Buy = 90;
input double RS_NVDA_RSI_Target_Sell = 70;
input int RS_NVDA_BarsToWait = 5;
input double RS_NVDA_LotSize = 50;
input int RS_NVDA_MagicNumber = 20003;
input int RS_NVDA_Slippage = 3;
input group "=== RSI Scalping TSLA - Pepperstone US ==="
input string RS_TSLA_Symbol = "TSLA.US"; // Try: "TSLA.US", "NASDAQ:TSLA", or "TSLA"
input ENUM_TIMEFRAMES RS_TSLA_TimeFrame = PERIOD_H1;
input int RS_TSLA_RSI_Period = 14;
input ENUM_APPLIED_PRICE RS_TSLA_RSI_Applied_Price = PRICE_CLOSE;
input double RS_TSLA_RSI_Overbought = 54;
input double RS_TSLA_RSI_Oversold = 73;
input double RS_TSLA_RSI_Target_Buy = 87;
input double RS_TSLA_RSI_Target_Sell = 33;
input int RS_TSLA_BarsToWait = 1;
input double RS_TSLA_LotSize = 50;
input int RS_TSLA_MagicNumber = 125421321;
input int RS_TSLA_Slippage = 3;
input group "=== RSI Scalping XAUUSD ==="
input string RS_XAUUSD_Symbol = "XAUUSD";
input ENUM_TIMEFRAMES RS_XAUUSD_TimeFrame = PERIOD_H1;
input int RS_XAUUSD_RSI_Period = 14;
input ENUM_APPLIED_PRICE RS_XAUUSD_RSI_Applied_Price = PRICE_CLOSE;
input double RS_XAUUSD_RSI_Overbought = 71;
input double RS_XAUUSD_RSI_Oversold = 57;
input double RS_XAUUSD_RSI_Target_Buy = 80;
input double RS_XAUUSD_RSI_Target_Sell = 57;
input int RS_XAUUSD_BarsToWait = 4;
input double RS_XAUUSD_LotSize = 0.1;
input int RS_XAUUSD_MagicNumber = 129102315;
input int RS_XAUUSD_Slippage = 3;
input group "=== RSI Scalping Reversal escape (XAUUSD) ==="
input bool RS_UseReversalEscape = false;
input int RS_ReversalATRPeriod = 14;
input double RS_ReversalAdverseAtrMult = 5.25;
input int RS_ReversalSignsRequired = 2;
input double RS_ReversalRsiVelocity = 16.0;
input double RS_ReversalBodyAtrMult = 5.1;
input group "=== RSI Scalping APPL — Trailing ==="
input bool RS_APPL_UseTrailingStop = true;
input double RS_APPL_TrailDistancePoints = 120.0;
input double RS_APPL_TrailActivationPoints = 0.0;
input group "=== RSI Scalping BTCUSD — Trailing ==="
input bool RS_BTCUSD_UseTrailingStop = true;
input double RS_BTCUSD_TrailDistancePoints = 120.0;
input double RS_BTCUSD_TrailActivationPoints = 0.0;
input group "=== RSI Scalping MSFT — Trailing ==="
input bool RS_MSFT_UseTrailingStop = true;
input double RS_MSFT_TrailDistancePoints = 375.0;
input double RS_MSFT_TrailActivationPoints = 75.0;
input group "=== RSI Scalping NVDA — Trailing ==="
input bool RS_NVDA_UseTrailingStop = true;
input double RS_NVDA_TrailDistancePoints = 375.0;
input double RS_NVDA_TrailActivationPoints = 75.0;
input group "=== RSI Scalping TSLA — Trailing ==="
input bool RS_TSLA_UseTrailingStop = true;
input double RS_TSLA_TrailDistancePoints = 900.0;
input double RS_TSLA_TrailActivationPoints = 950.0;
input group "=== RSI Scalping XAUUSD — Trailing ==="
input bool RS_XAUUSD_UseTrailingStop = true;
input double RS_XAUUSD_TrailDistancePoints = 71.0;
input double RS_XAUUSD_TrailActivationPoints = 41.0;
//+------------------------------------------------------------------+
//| Global Variables - DarvasBox |
//+------------------------------------------------------------------+
struct DarvasBoxData {
string symbol;
bool isInitialized;
double boxHigh;
double boxLow;
bool boxFormed;
datetime lastBoxTime;
string boxName;
double minStopLevel;
double point;
CTrade trade;
int maHandle;
int volumeHandle;
datetime lastBarTime;
};
//+------------------------------------------------------------------+
//| Global Variables - EMA Slope Distance |
//+------------------------------------------------------------------+
struct EMASlopeData {
string symbol;
bool isInitialized;
int ema_handle;
double ema_array[];
datetime letzte_überwachung_zeit;
bool überwachung_aktiv;
bool preis_trigger_aktiv;
bool steigung_trigger_aktiv;
int ticket;
CTrade trade;
int trades_in_current_crossover;
bool crossover_detected;
datetime trade_open_time;
datetime last_bar_time;
datetime es_last_sl_adjust_success_time;
};
//+------------------------------------------------------------------+
//| Global Variables - RSI CrossOver Reversal |
//+------------------------------------------------------------------+
struct RSICrossOverData {
string symbol;
bool isInitialized;
int rsiHandle;
int emaHandle;
double previousRSIDef;
CTrade trade;
datetime lastTradeTime;
datetime bartime;
bool WeekDays[7];
datetime lastBarTime;
};
//+------------------------------------------------------------------+
//| Global Variables - RSI MidPoint Hijack |
//+------------------------------------------------------------------+
struct RSIMidPointData {
string symbol;
bool isInitialized;
int rsiHandle;
int rsiReverseHandle;
int emaHandle;
bool rsiOverbought;
bool rsiOversold;
bool rsiReverseOverbought;
bool rsiReverseOversold;
CTrade trade;
CPositionInfo positionInfo;
bool emaCrossBuySignal;
bool emaCrossSellSignal;
int emaCrossSignalBar;
datetime lastBarTime;
datetime rsiReverseLastCloseTime;
bool rsiReverseInCooldown;
double lastBarRSI;
double lastBarRSIReverse;
double lastBarEMA;
double lastBarClose;
double lastBarEMAPrev;
double lastBarClosePrev;
};
//+------------------------------------------------------------------+
//| Global Variables - RSI Scalping |
//+------------------------------------------------------------------+
struct RSIScalpingData {
string symbol;
bool isInitialized;
CTrade trade;
int rsi_handle;
double rsi_buffer[];
double rsi_prev;
double rsi_current;
double rsi_two_bars_ago;
bool position_open;
ulong position_ticket;
ENUM_POSITION_TYPE current_position_type;
datetime last_bar_time;
bool rsi_against_position;
int bars_against_count;
};
//+------------------------------------------------------------------+
//| Global Strategy Instances |
//+------------------------------------------------------------------+
DarvasBoxData dbData;
EMASlopeData esData;
RSICrossOverData rcData;
RSIMidPointData rmData;
RSIScalpingData rsAPPLData;
RSIScalpingData rsBTCUSDData;
RSIScalpingData rsMSFTData;
RSIScalpingData rsNVDAData;
RSIScalpingData rsTSLAData;
RSIScalpingData rsXAUUSDData;
//+------------------------------------------------------------------+
//| Global Variables for lot sizes (from inputs below) |
//+------------------------------------------------------------------+
double g_DB_LotSize = 0.01;
double g_ES_LotSize;
double g_RC_LotSize;
double g_RM_LotSize;
double g_RS_APPL_LotSize;
double g_RS_BTCUSD_LotSize;
double g_RS_MSFT_LotSize;
double g_RS_NVDA_LotSize;
double g_RS_TSLA_LotSize;
double g_RS_XAUUSD_LotSize;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
int initResult = INIT_SUCCEEDED;
g_ES_LotSize = ES_LotGröße;
g_RC_LotSize = RC_lotSize;
g_RM_LotSize = RM_InpLotSize;
g_RS_APPL_LotSize = RS_APPL_LotSize;
g_RS_BTCUSD_LotSize = RS_BTCUSD_LotSize;
g_RS_MSFT_LotSize = RS_MSFT_LotSize;
g_RS_NVDA_LotSize = RS_NVDA_LotSize;
g_RS_TSLA_LotSize = RS_TSLA_LotSize;
g_RS_XAUUSD_LotSize = RS_XAUUSD_LotSize;
if(EnableDarvasBox)
if(!InitDarvasBox(DB_Symbol))
Print("Warning: DarvasBox strategy failed to initialize for symbol '", DB_Symbol, "'");
if(EnableEMASlopeDistance)
if(!InitEMASlopeDistance(ES_Symbol))
Print("Warning: EMASlopeDistance strategy failed to initialize for symbol '", ES_Symbol, "'");
if(EnableRSICrossOverReversal)
if(!InitRSICrossOverReversal(RC_Symbol))
Print("Warning: RSICrossOverReversal strategy failed to initialize for symbol '", RC_Symbol, "'");
if(EnableRSIMidPointHijack)
if(!InitRSIMidPointHijack(RM_Symbol))
Print("Warning: RSIMidPointHijack strategy failed to initialize for symbol '", RM_Symbol, "'");
if(EnableRSIScalpingAPPL)
InitRSIScalping(rsAPPLData, RS_APPL_Symbol, RS_APPL_TimeFrame, RS_APPL_RSI_Period, RS_APPL_RSI_Applied_Price, RS_APPL_MagicNumber, RS_APPL_Slippage);
if(EnableRSIScalpingBTCUSD)
InitRSIScalping(rsBTCUSDData, RS_BTCUSD_Symbol, RS_BTCUSD_TimeFrame, RS_BTCUSD_RSI_Period, RS_BTCUSD_RSI_Applied_Price, RS_BTCUSD_MagicNumber, RS_BTCUSD_Slippage);
if(EnableRSIScalpingMSFT)
InitRSIScalping(rsMSFTData, RS_MSFT_Symbol, RS_MSFT_TimeFrame, RS_MSFT_RSI_Period, RS_MSFT_RSI_Applied_Price, RS_MSFT_MagicNumber, RS_MSFT_Slippage);
if(EnableRSIScalpingNVDA)
InitRSIScalping(rsNVDAData, RS_NVDA_Symbol, RS_NVDA_TimeFrame, RS_NVDA_RSI_Period, RS_NVDA_RSI_Applied_Price, RS_NVDA_MagicNumber, RS_NVDA_Slippage);
if(EnableRSIScalpingTSLA)
InitRSIScalping(rsTSLAData, RS_TSLA_Symbol, RS_TSLA_TimeFrame, RS_TSLA_RSI_Period, RS_TSLA_RSI_Applied_Price, RS_TSLA_MagicNumber, RS_TSLA_Slippage);
if(EnableRSIScalpingXAUUSD)
InitRSIScalping(rsXAUUSDData, RS_XAUUSD_Symbol, RS_XAUUSD_TimeFrame, RS_XAUUSD_RSI_Period, RS_XAUUSD_RSI_Applied_Price, RS_XAUUSD_MagicNumber, RS_XAUUSD_Slippage);
Print("United EA (self-evaluate build) initialized. Active strategies: ",
(EnableDarvasBox ? "DarvasBox " : ""),
(EnableEMASlopeDistance ? "EMASlope " : ""),
(EnableRSICrossOverReversal ? "RSICrossOver " : ""),
(EnableRSIMidPointHijack ? "RSIMidPoint " : ""),
(EnableRSIScalpingAPPL ? "RSIScalpingAPPL " : ""),
(EnableRSIScalpingBTCUSD ? "RSIScalpingBTCUSD " : ""),
(EnableRSIScalpingMSFT ? "RSIScalpingMSFT " : ""),
(EnableRSIScalpingNVDA ? "RSIScalpingNVDA " : ""),
(EnableRSIScalpingTSLA ? "RSIScalpingTSLA " : ""),
(EnableRSIScalpingXAUUSD ? "RSIScalpingXAUUSD " : ""));
return initResult;
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if(EnableDarvasBox)
DeinitDarvasBox();
if(EnableEMASlopeDistance)
DeinitEMASlopeDistance();
if(EnableRSICrossOverReversal)
DeinitRSICrossOverReversal();
if(EnableRSIMidPointHijack)
DeinitRSIMidPointHijack();
if(EnableRSIScalpingAPPL)
DeinitRSIScalping(rsAPPLData);
if(EnableRSIScalpingBTCUSD)
DeinitRSIScalping(rsBTCUSDData);
if(EnableRSIScalpingMSFT)
DeinitRSIScalping(rsMSFTData);
if(EnableRSIScalpingNVDA)
DeinitRSIScalping(rsNVDAData);
if(EnableRSIScalpingTSLA)
DeinitRSIScalping(rsTSLAData);
if(EnableRSIScalpingXAUUSD)
DeinitRSIScalping(rsXAUUSDData);
Print("United EA deinitialized. Reason: ", reason);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
if(EnableDarvasBox)
ProcessDarvasBox(DB_Symbol);
if(EnableEMASlopeDistance)
ProcessEMASlopeDistance(ES_Symbol);
if(EnableRSICrossOverReversal)
ProcessRSICrossOverReversal(RC_Symbol);
if(EnableRSIMidPointHijack)
ProcessRSIMidPointHijack(RM_Symbol);
if(EnableRSIScalpingAPPL)
ProcessRSIScalping(rsAPPLData, RS_APPL_Symbol, RS_APPL_TimeFrame, RS_APPL_RSI_Period, RS_APPL_RSI_Applied_Price,
RS_APPL_RSI_Overbought, RS_APPL_RSI_Oversold, RS_APPL_RSI_Target_Buy, RS_APPL_RSI_Target_Sell,
RS_APPL_BarsToWait, g_RS_APPL_LotSize, RS_APPL_MagicNumber,
false, RS_ReversalATRPeriod, RS_ReversalAdverseAtrMult, RS_ReversalSignsRequired,
RS_ReversalRsiVelocity, RS_ReversalBodyAtrMult,
RS_APPL_UseTrailingStop, RS_APPL_TrailDistancePoints, RS_APPL_TrailActivationPoints);
if(EnableRSIScalpingBTCUSD)
ProcessRSIScalping(rsBTCUSDData, RS_BTCUSD_Symbol, RS_BTCUSD_TimeFrame, RS_BTCUSD_RSI_Period, RS_BTCUSD_RSI_Applied_Price,
RS_BTCUSD_RSI_Overbought, RS_BTCUSD_RSI_Oversold, RS_BTCUSD_RSI_Target_Buy, RS_BTCUSD_RSI_Target_Sell,
RS_BTCUSD_BarsToWait, g_RS_BTCUSD_LotSize, RS_BTCUSD_MagicNumber,
false, RS_ReversalATRPeriod, RS_ReversalAdverseAtrMult, RS_ReversalSignsRequired,
RS_ReversalRsiVelocity, RS_ReversalBodyAtrMult,
RS_BTCUSD_UseTrailingStop, RS_BTCUSD_TrailDistancePoints, RS_BTCUSD_TrailActivationPoints);
if(EnableRSIScalpingMSFT)
ProcessRSIScalping(rsMSFTData, RS_MSFT_Symbol, RS_MSFT_TimeFrame, RS_MSFT_RSI_Period, RS_MSFT_RSI_Applied_Price,
RS_MSFT_RSI_Overbought, RS_MSFT_RSI_Oversold, RS_MSFT_RSI_Target_Buy, RS_MSFT_RSI_Target_Sell,
RS_MSFT_BarsToWait, g_RS_MSFT_LotSize, RS_MSFT_MagicNumber,
false, RS_ReversalATRPeriod, RS_ReversalAdverseAtrMult, RS_ReversalSignsRequired,
RS_ReversalRsiVelocity, RS_ReversalBodyAtrMult,
RS_MSFT_UseTrailingStop, RS_MSFT_TrailDistancePoints, RS_MSFT_TrailActivationPoints);
if(EnableRSIScalpingNVDA)
ProcessRSIScalping(rsNVDAData, RS_NVDA_Symbol, RS_NVDA_TimeFrame, RS_NVDA_RSI_Period, RS_NVDA_RSI_Applied_Price,
RS_NVDA_RSI_Overbought, RS_NVDA_RSI_Oversold, RS_NVDA_RSI_Target_Buy, RS_NVDA_RSI_Target_Sell,
RS_NVDA_BarsToWait, g_RS_NVDA_LotSize, RS_NVDA_MagicNumber,
false, RS_ReversalATRPeriod, RS_ReversalAdverseAtrMult, RS_ReversalSignsRequired,
RS_ReversalRsiVelocity, RS_ReversalBodyAtrMult,
RS_NVDA_UseTrailingStop, RS_NVDA_TrailDistancePoints, RS_NVDA_TrailActivationPoints);
if(EnableRSIScalpingTSLA)
ProcessRSIScalping(rsTSLAData, RS_TSLA_Symbol, RS_TSLA_TimeFrame, RS_TSLA_RSI_Period, RS_TSLA_RSI_Applied_Price,
RS_TSLA_RSI_Overbought, RS_TSLA_RSI_Oversold, RS_TSLA_RSI_Target_Buy, RS_TSLA_RSI_Target_Sell,
RS_TSLA_BarsToWait, g_RS_TSLA_LotSize, RS_TSLA_MagicNumber,
false, RS_ReversalATRPeriod, RS_ReversalAdverseAtrMult, RS_ReversalSignsRequired,
RS_ReversalRsiVelocity, RS_ReversalBodyAtrMult,
RS_TSLA_UseTrailingStop, RS_TSLA_TrailDistancePoints, RS_TSLA_TrailActivationPoints);
if(EnableRSIScalpingXAUUSD)
ProcessRSIScalping(rsXAUUSDData, RS_XAUUSD_Symbol, RS_XAUUSD_TimeFrame, RS_XAUUSD_RSI_Period, RS_XAUUSD_RSI_Applied_Price,
RS_XAUUSD_RSI_Overbought, RS_XAUUSD_RSI_Oversold, RS_XAUUSD_RSI_Target_Buy, RS_XAUUSD_RSI_Target_Sell,
RS_XAUUSD_BarsToWait, g_RS_XAUUSD_LotSize, RS_XAUUSD_MagicNumber,
RS_UseReversalEscape, RS_ReversalATRPeriod, RS_ReversalAdverseAtrMult, RS_ReversalSignsRequired,
RS_ReversalRsiVelocity, RS_ReversalBodyAtrMult,
RS_XAUUSD_UseTrailingStop, RS_XAUUSD_TrailDistancePoints, RS_XAUUSD_TrailActivationPoints);
}
//+------------------------------------------------------------------+
//| Include strategy implementations |
//+------------------------------------------------------------------+
#include "Strategies/DarvasBoxStrategy.mqh"
#include "Strategies/EMASlopeDistanceStrategy.mqh"
#include "Strategies/RSICrossOverReversalStrategy.mqh"
#include "Strategies/RSIMidPointHijackStrategy.mqh"
#include "Strategies/RSIScalpingStrategy.mqh"
//+------------------------------------------------------------------+
@@ -5,29 +5,24 @@
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.01"
#property version "1.00"
#include <Trade\Trade.mqh>
#include "../_united/MagicNumberHelpers.mqh"
//--- Input parameters
input ENUM_TIMEFRAMES TimeFrame = PERIOD_H1; // Timeframe for Analysis
//--- Input parameters — synced with Desktop 123.set (2026.05.13)
input ENUM_TIMEFRAMES TimeFrame = PERIOD_M20; // Timeframe for Analysis
input int RSI_Period = 14; // RSI Period
input ENUM_APPLIED_PRICE RSI_Applied_Price = PRICE_CLOSE; // RSI Applied Price
input double RSI_Overbought = 54; // RSI Overbought Level
input double RSI_Oversold = 73; // RSI Oversold Level
input double RSI_Target_Buy = 87; // RSI Target for Buy Exit
input double RSI_Target_Sell = 33; // RSI Target for Sell Exit
input int BarsToWait = 1; // Bars to wait when RSI goes against position
input double RSI_Overbought = 32; // RSI Overbought Level
input double RSI_Oversold = 86; // RSI Oversold Level
input double RSI_Target_Buy = 100; // RSI Target for Buy Exit
input double RSI_Target_Sell = 24; // RSI Target for Sell Exit
input int BarsToWait = 34; // Bars to wait when RSI goes against position
input double LotSize = 5; // Lot Size
input int MagicNumber = 125421321; // Magic Number
input int MagicNumber = 129102315; // Magic Number
input int Slippage = 3; // Slippage in points
input group "=== Trailing stop ==="
input bool UseTrailingStop = true; // move SL behind bid/ask while in profit
input double TrailingStopDistancePoints = 900.0; // SL distance from bid/ask (points)
input double TrailingActivationPoints = 950.0; // min profit before trailing (0 = same as distance)
//--- Global variables
CTrade trade;
int rsi_handle;
@@ -77,32 +72,35 @@ void OnDeinit(const int reason)
//+------------------------------------------------------------------+
void OnTick()
{
// Check if we have enough bars
if(Bars(_Symbol, TimeFrame) < RSI_Period + 2)
{
return;
const datetime current_bar_time = iTime(_Symbol, TimeFrame, 0);
const bool new_bar = (current_bar_time != last_bar_time);
const bool in_pos = position_open || PositionExistsByMagic(_Symbol, (ulong)MagicNumber);
if(!in_pos && !new_bar)
return;
if(!UpdateRSI())
return;
if(in_pos && UseTrailingStop)
ApplyTrailingStop();
if(!new_bar)
return;
}
// Check if this is a new bar
datetime current_bar_time = iTime(_Symbol, TimeFrame, 0);
if(current_bar_time == last_bar_time)
{
return; // Still the same bar, don't process
}
last_bar_time = current_bar_time;
ResyncPositionFromMarket();
// Update RSI values
if(!UpdateRSI())
{
return;
}
// Check for existing position
CheckExistingPosition();
if(!position_open && !PositionExistsByMagic(_Symbol, (ulong)MagicNumber))
// 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();
}
}
//+------------------------------------------------------------------+
@@ -122,85 +120,6 @@ bool UpdateRSI()
return true;
}
//+------------------------------------------------------------------+
//| Trail SL behind favorable price (every tick when enabled) |
//+------------------------------------------------------------------+
void ApplyTrailingStop()
{
if(TrailingStopDistancePoints <= 0.0)
return;
if(!PositionSelectByMagic(_Symbol, (ulong)MagicNumber))
return;
const double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
if(point <= 0.0)
return;
const int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
const double trail_dist = TrailingStopDistancePoints * point;
const double activation_pts = (TrailingActivationPoints > 0.0)
? TrailingActivationPoints
: TrailingStopDistancePoints;
const double activation = activation_pts * point;
const long stops_level = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
const double min_dist = (double)stops_level * point;
const ENUM_POSITION_TYPE ptype = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
const double entry = PositionGetDouble(POSITION_PRICE_OPEN);
const double cur_sl = PositionGetDouble(POSITION_SL);
const double cur_tp = PositionGetDouble(POSITION_TP);
if(ptype == POSITION_TYPE_BUY)
{
const double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
if(bid - entry <= activation)
return;
double new_sl = NormalizeDouble(bid - trail_dist, digits);
if(min_dist > 0.0 && bid - new_sl < min_dist)
new_sl = NormalizeDouble(bid - min_dist, digits);
if(new_sl >= bid || new_sl <= 0.0)
return;
if(cur_sl > 0.0 && new_sl <= cur_sl)
return;
ModifyPositionByMagic(trade, _Symbol, (ulong)MagicNumber, new_sl, cur_tp);
}
else if(ptype == POSITION_TYPE_SELL)
{
const double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
if(entry - ask <= activation)
return;
double new_sl = NormalizeDouble(ask + trail_dist, digits);
if(min_dist > 0.0 && new_sl - ask < min_dist)
new_sl = NormalizeDouble(ask + min_dist, digits);
if(new_sl <= ask || new_sl <= 0.0)
return;
if(cur_sl > 0.0 && new_sl >= cur_sl)
return;
ModifyPositionByMagic(trade, _Symbol, (ulong)MagicNumber, new_sl, cur_tp);
}
}
//+------------------------------------------------------------------+
//| Sync ticket/state if a position exists after restart |
//+------------------------------------------------------------------+
void ResyncPositionFromMarket()
{
if(position_open)
return;
ulong t = GetPositionTicketByMagic(_Symbol, (ulong)MagicNumber);
if(t == 0 || !PositionSelectByTicket(t))
return;
position_ticket = (int)t;
position_open = true;
current_position_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
}
//+------------------------------------------------------------------+
//| Check existing position for exit conditions |
//+------------------------------------------------------------------+
@@ -212,7 +131,7 @@ void CheckExistingPosition()
}
// Check if position still exists with correct magic number AND symbol for THIS EA
if(!PositionSelectByTicketSymbolAndMagic(position_ticket, _Symbol, (ulong)MagicNumber))
if(!PositionSelectByTicketSymbolAndMagic(position_ticket, _Symbol, MagicNumber))
{
position_open = false;
position_ticket = 0;
@@ -324,7 +243,7 @@ void CheckEntrySignals()
void OpenBuyPosition()
{
// Verify no position exists for THIS EA (magic number) on THIS symbol before opening
if(PositionExistsByMagic(_Symbol, (ulong)MagicNumber))
if(PositionExistsByMagic(_Symbol, MagicNumber))
{
return; // Position already exists for this EA
}
@@ -337,7 +256,7 @@ void OpenBuyPosition()
if(new_ticket > 0)
{
// Verify position was opened for THIS EA (magic number) on THIS symbol
if(PositionSelectByTicketSymbolAndMagic(new_ticket, _Symbol, (ulong)MagicNumber))
if(PositionSelectByTicketSymbolAndMagic(new_ticket, _Symbol, MagicNumber))
{
position_ticket = new_ticket;
position_open = true;
@@ -357,7 +276,7 @@ void OpenBuyPosition()
void OpenSellPosition()
{
// Verify no position exists for THIS EA (magic number) on THIS symbol before opening
if(PositionExistsByMagic(_Symbol, (ulong)MagicNumber))
if(PositionExistsByMagic(_Symbol, MagicNumber))
{
return; // Position already exists for this EA
}
@@ -370,7 +289,7 @@ void OpenSellPosition()
if(new_ticket > 0)
{
// Verify position was opened for THIS EA (magic number) on THIS symbol
if(PositionSelectByTicketSymbolAndMagic(new_ticket, _Symbol, (ulong)MagicNumber))
if(PositionSelectByTicketSymbolAndMagic(new_ticket, _Symbol, MagicNumber))
{
position_ticket = new_ticket;
position_open = true;
@@ -390,7 +309,7 @@ void OpenSellPosition()
void ClosePosition()
{
// Close position using helper that verifies symbol AND magic number for THIS EA
if(ClosePositionByMagic(trade, _Symbol, (ulong)MagicNumber))
if(ClosePositionByMagic(trade, _Symbol, MagicNumber))
{
position_open = false;
position_ticket = 0;

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

@@ -40,6 +40,7 @@ double g_Pos_RS_BTCUSD;
double g_Pos_RS_NVDA;
double g_Pos_RS_TSLA;
double g_Pos_RS_XAUUSD;
double g_Pos_RS_MU;
double g_Pos_RRA_EURUSD;
double g_Pos_RRA_AUDUSD;
double g_Pos_SE;
@@ -65,44 +66,47 @@ input bool EnableEMASlopeDistance = true;
input bool EnableRSICrossOverReversal = true;
input bool EnableRSIMidPointHijack = true;
input bool EnableRSIScalpingAPPL = true;
input bool EnableRSIScalpingBTCUSD = true;
input bool EnableRSIScalpingBTCUSD = false;
input bool EnableRSIScalpingNVDA = true;
input bool EnableRSIScalpingTSLA = true;
input bool EnableRSIScalpingXAUUSD = true;
input bool EnableSuperEMA = true;
input bool EnableRSIConsolidation = true;
input bool EnableRSIScalpingXAUUSD = false;
input bool EnableRSIScalpingMU = true;
input bool EnableSuperEMA = false;
input bool EnableRSIConsolidation = false;
input bool EnableRSIReversalAsianEURUSD = true;
input bool EnableRSIReversalAsianAUDUSD = true;
input bool EnableSimpleTrendlineBTCUSD = true;
input bool EnableSimpleTrendlineXAUUSD = true;
input bool EnableSimpleTrendlineGER40 = true;
input bool EnableRSISecretSauce = true;
input bool EnableSimpleTrendlineBTCUSD = false;
input bool EnableSimpleTrendlineXAUUSD = false;
input bool EnableSimpleTrendlineGER40 = false;
input bool EnableRSISecretSauce = false;
input bool OPT_GuardOptimizationMode = true; // legacy compatibility with 123.set
input group "=== Centralized Lot Size (Granular Per Robot) ==="
input double LOT_DB_DarvasBox = 0.05;
input double LOT_ES_EMASlopeDistance = 0.05;
input double LOT_RC_RSICrossOver = 0.06;
input double LOT_RM_RSIMidPointHijack = 0.03;
input double LOT_RS_APPL = 5.0;
input double LOT_DB_DarvasBox = 0.01;
input double LOT_ES_EMASlopeDistance = 0.02;
input double LOT_RC_RSICrossOver = 0.01;
input double LOT_RM_RSIMidPointHijack = 0.01;
input double LOT_RS_APPL = 25.0;
input double LOT_RS_BTCUSD = 0.1;
input double LOT_RS_NVDA = 10.0;
input double LOT_RS_TSLA = 15.0;
input double LOT_RS_XAUUSD = 0.1;
input double LOT_RRA_EURUSD = 0.05;
input double LOT_RRA_AUDUSD = 0.08;
input double LOT_SE_SuperEMA = 0.02;
input double LOT_RCO_RSIConsolidation = 0.02;
input double LOT_ST_BTCUSD = 0.07;
input double LOT_ST_XAUUSD = 0.01;
input double LOT_RS_NVDA = 25.0;
input double LOT_RS_TSLA = 5.0;
input double LOT_RS_XAUUSD = 0.27;
input double LOT_RS_MU = 5.0;
input double LOT_RRA_EURUSD = 0.1;
input double LOT_RRA_AUDUSD = 0.1;
input double LOT_SE_SuperEMA = 0.01;
input double LOT_RCO_RSIConsolidation = 0.1;
input double LOT_ST_BTCUSD = 0.1;
input double LOT_ST_XAUUSD = 0.1;
input double LOT_ST_GER40 = 0.10;
input double LOT_RSS_SecretSauce = 0.01;
input double LOT_RSS_SecretSauce = 0.1;
input group "=== Balance-based position sizing ==="
input bool ORCH_ScaleLotsByBalance = true;
input bool ORCH_UseEquityInsteadOfBalance = false;
input double ORCH_ReferenceBalance = 10000.0;
input double ORCH_ReferenceBalance = 1000.0;
input double ORCH_MinBalanceScale = 0.1;
input double ORCH_MaxBalanceScale = 10.0;
input double ORCH_MaxBalanceScale = 100000.0;
//+------------------------------------------------------------------+
//| Strategy 1: DarvasBoxXAUUSD |
@@ -143,7 +147,7 @@ input bool ES_UseTrailingStop = true;
input double ES_TrailingActivationPips = 0.0;
input bool ES_UseStaleStopLossExit = false;
input int ES_StaleStopLossSeconds = 33800;
input double ES_LotGröße = 0.03;
input double ES_LotGröße = 0.07;
input int ES_MagicNumber = 12350;
input bool ES_UseSpreadAdjustment = true;
input ENUM_TIMEFRAMES ES_Timeframe = PERIOD_H1;
@@ -169,7 +173,7 @@ input int RC_overboughtLevel = 93;
input int RC_oversoldLevel = 22;
input double RC_entryRSIBuySpread = 0;
input double RC_entryRSISellSpread = 0;
input double RC_lotSize = 0.01;
input double RC_lotSize = 0.1;
input int RC_slippage = 3;
input int RC_cooldownSeconds = 209;
input ENUM_TIMEFRAMES RC_TimeFrame1 = PERIOD_M1;
@@ -201,7 +205,7 @@ input bool RC_Saturday = false;
input group "=== RSI MidPoint Hijack Strategy ==="
input string RM_Symbol = "XAUUSD";
input ENUM_TIMEFRAMES RM_InpTimeframe = PERIOD_H1;
input double RM_InpLotSize = 0.02;
input double RM_InpLotSize = 0.1;
input int RM_InpMagicNumberRSIFollow = 1001;
input int RM_InpMagicNumberRSIReverse = 1002;
input int RM_InpMagicNumberEMACross = 1003;
@@ -254,7 +258,7 @@ input int RM_InpEMADistancePeriod = 26;
//| 4. Use the exact symbol name shown |
//+------------------------------------------------------------------+
input group "=== RSI Scalping APPL (AAPL) - Pepperstone US ==="
input string RS_APPL_Symbol = "AAPL.NAS"; // Pepperstone / match tester set (also try AAPL.US)
input string RS_APPL_Symbol = "AAPL";
input ENUM_TIMEFRAMES RS_APPL_TimeFrame = PERIOD_M10;
input int RS_APPL_RSI_Period = 14;
input ENUM_APPLIED_PRICE RS_APPL_RSI_Applied_Price = PRICE_CLOSE;
@@ -282,7 +286,7 @@ input int RS_BTCUSD_MagicNumber = 123459123;
input int RS_BTCUSD_Slippage = 3;
input group "=== RSI Scalping NVDA - Pepperstone US ==="
input string RS_NVDA_Symbol = "NVDA.NAS"; // Pepperstone / match tester set (also try NVDA.US)
input string RS_NVDA_Symbol = "NVDA";
input ENUM_TIMEFRAMES RS_NVDA_TimeFrame = PERIOD_M15;
input int RS_NVDA_RSI_Period = 8;
input ENUM_APPLIED_PRICE RS_NVDA_RSI_Applied_Price = PRICE_CLOSE;
@@ -291,12 +295,12 @@ input double RS_NVDA_RSI_Oversold = 38;
input double RS_NVDA_RSI_Target_Buy = 90;
input double RS_NVDA_RSI_Target_Sell = 70;
input int RS_NVDA_BarsToWait = 5;
input double RS_NVDA_LotSize = 50;
input double RS_NVDA_LotSize = 5;
input int RS_NVDA_MagicNumber = 20003;
input int RS_NVDA_Slippage = 3;
input group "=== RSI Scalping TSLA - Pepperstone US ==="
input string RS_TSLA_Symbol = "TSLA.NAS"; // Pepperstone / match tester set (also try TSLA.US)
input string RS_TSLA_Symbol = "TSLA";
input ENUM_TIMEFRAMES RS_TSLA_TimeFrame = PERIOD_H1;
input int RS_TSLA_RSI_Period = 14;
input ENUM_APPLIED_PRICE RS_TSLA_RSI_Applied_Price = PRICE_CLOSE;
@@ -305,7 +309,7 @@ input double RS_TSLA_RSI_Oversold = 73;
input double RS_TSLA_RSI_Target_Buy = 87;
input double RS_TSLA_RSI_Target_Sell = 33;
input int RS_TSLA_BarsToWait = 1;
input double RS_TSLA_LotSize = 50;
input double RS_TSLA_LotSize = 5;
input int RS_TSLA_MagicNumber = 125421321;
input int RS_TSLA_Slippage = 3;
@@ -323,6 +327,20 @@ input double RS_XAUUSD_LotSize = 0.1;
input int RS_XAUUSD_MagicNumber = 129102315;
input int RS_XAUUSD_Slippage = 3;
input group "=== RSI Scalping MU ==="
input string RS_MU_Symbol = "MU";
input ENUM_TIMEFRAMES RS_MU_TimeFrame = PERIOD_M20;
input int RS_MU_RSI_Period = 14;
input ENUM_APPLIED_PRICE RS_MU_RSI_Applied_Price = PRICE_CLOSE;
input double RS_MU_RSI_Overbought = 32;
input double RS_MU_RSI_Oversold = 86;
input double RS_MU_RSI_Target_Buy = 100;
input double RS_MU_RSI_Target_Sell = 24;
input int RS_MU_BarsToWait = 34;
input double RS_MU_LotSize = 5.0;
input int RS_MU_MagicNumber = 129102316;
input int RS_MU_Slippage = 3;
input group "=== RSI Scalping Reversal Escape (XAUUSD only) ==="
input bool RS_UseReversalEscape = true;
input int RS_ReversalATRPeriod = 14;
@@ -480,7 +498,7 @@ input ENUM_APPLIED_PRICE ST_XAU_AppliedPrice = PRICE_OPEN;
input int ST_XAU_HTFBarsToScan = 500;
input double ST_XAU_LineTouchTolerance = 220.0;
input double ST_XAU_BreakBuffer = 110.0;
input ulong ST_XAU_MagicNumber = 26042503;
input ulong ST_XAU_MagicNumber = 26042501;
input bool ST_XAU_DrawTrendline = true;
input group "=== SimpleTrendline GER40 ==="
@@ -549,6 +567,7 @@ void United_RefreshScaledLots()
g_Pos_RS_NVDA = United_ScaledLot(LOT_RS_NVDA);
g_Pos_RS_TSLA = United_ScaledLot(LOT_RS_TSLA);
g_Pos_RS_XAUUSD = United_ScaledLot(LOT_RS_XAUUSD);
g_Pos_RS_MU = United_ScaledLot(LOT_RS_MU);
g_Pos_RRA_EURUSD = United_ScaledLot(LOT_RRA_EURUSD);
g_Pos_RRA_AUDUSD = United_ScaledLot(LOT_RRA_AUDUSD);
g_Pos_SE = United_ScaledLot(LOT_SE_SuperEMA);
@@ -656,6 +675,7 @@ RSIScalpingData rsBTCUSDData;
RSIScalpingData rsNVDAData;
RSIScalpingData rsTSLAData;
RSIScalpingData rsXAUUSDData;
RSIScalpingData rsMUData;
SuperEMAData seData;
RSIConsolidationData rcoData;
SimpleTrendlineData stBTCData;
@@ -710,6 +730,8 @@ int OnInit()
if(EnableRSIScalpingXAUUSD)
InitRSIScalping(rsXAUUSDData, RS_XAUUSD_Symbol, RS_XAUUSD_TimeFrame, RS_XAUUSD_RSI_Period, RS_XAUUSD_RSI_Applied_Price, RS_XAUUSD_MagicNumber, RS_XAUUSD_Slippage);
if(EnableRSIScalpingMU)
InitRSIScalping(rsMUData, RS_MU_Symbol, RS_MU_TimeFrame, RS_MU_RSI_Period, RS_MU_RSI_Applied_Price, RS_MU_MagicNumber, RS_MU_Slippage);
if(EnableRSISecretSauce)
if(!InitRSISecretSauce(rssData, RSS_Symbol))
@@ -779,6 +801,7 @@ int OnInit()
(EnableRSIScalpingNVDA ? "RSIScalpingNVDA " : ""),
(EnableRSIScalpingTSLA ? "RSIScalpingTSLA " : ""),
(EnableRSIScalpingXAUUSD ? "RSIScalpingXAUUSD " : ""),
(EnableRSIScalpingMU ? "RSIScalpingMU " : ""),
(EnableRSISecretSauce ? "RSISecretSauce " : ""),
(EnableSuperEMA ? "SuperEMA " : ""),
(EnableRSIConsolidation ? "RSIConsolidation " : ""),
@@ -822,6 +845,8 @@ void OnDeinit(const int reason)
if(EnableRSIScalpingXAUUSD)
DeinitRSIScalping(rsXAUUSDData);
if(EnableRSIScalpingMU)
DeinitRSIScalping(rsMUData);
if(EnableRSISecretSauce)
DeinitRSISecretSauce(rssData);
@@ -906,6 +931,13 @@ void OnTick()
RS_UseReversalEscape, RS_ReversalATRPeriod, RS_ReversalAdverseAtrMult, RS_ReversalSignsRequired,
RS_ReversalRsiVelocity, RS_ReversalBodyAtrMult,
RS_XAUUSD_UseTrailingStop, RS_XAUUSD_TrailDistancePoints, RS_XAUUSD_TrailActivationPoints);
if(EnableRSIScalpingMU)
ProcessRSIScalping(rsMUData, RS_MU_Symbol, RS_MU_TimeFrame, RS_MU_RSI_Period, RS_MU_RSI_Applied_Price,
RS_MU_RSI_Overbought, RS_MU_RSI_Oversold, RS_MU_RSI_Target_Buy, RS_MU_RSI_Target_Sell,
RS_MU_BarsToWait, g_Pos_RS_MU, RS_MU_MagicNumber,
false, RS_ReversalATRPeriod, RS_ReversalAdverseAtrMult, RS_ReversalSignsRequired,
RS_ReversalRsiVelocity, RS_ReversalBodyAtrMult,
false, 0.0, 0.0);
if(EnableRSISecretSauce)
ProcessRSISecretSauce(rssData, g_RSS_LotSize);

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.
Binary file not shown.
@@ -22,6 +22,16 @@ TimeFrame=16387||0||16385||16390||Y
; === PHASE 3: POSITION SIZING (Optimize with caution) ===
LotSize=50.0||5.0||10.0||100.0||Y
; === Trailing stop (main.mq5 1.01+) ===
UseTrailingStop=true||false||0||true||N
TrailingStopDistancePoints=375.0||25.0||100.0||800.0||Y
TrailingActivationPoints=75.0||5.0||0.0||300.0||Y
; === Session filter new entries UTC (main.mq5 1.02+) ===
UseSessionFilterUTC=false||false||0||true||Y
TradeStartHourUTC=9||1||6||14||Y
TradeEndHourUTC=22||1||18||24||N
; === FIXED PARAMETERS (Do Not Optimize) ===
RSI_Applied_Price=1||0||1||1||N
MagicNumber=12345||0||12345||12345||N
@@ -18,6 +18,16 @@ TimeFrame=16387||0||16385||16390||Y
; === PHASE 3: POSITION SIZING ===
LotSize=50.0||5.0||10.0||100.0||Y
; === Trailing stop (main.mq5 1.01+) ===
UseTrailingStop=true||false||0||true||N
TrailingStopDistancePoints=375.0||25.0||100.0||800.0||Y
TrailingActivationPoints=75.0||5.0||0.0||300.0||Y
; === Session filter new entries UTC (main.mq5 1.02+) ===
UseSessionFilterUTC=false||false||0||true||Y
TradeStartHourUTC=9||1||6||14||Y
TradeEndHourUTC=22||1||18||24||N
; === FIXED PARAMETERS ===
RSI_Applied_Price=1||0||1||1||N
MagicNumber=12345||0||12345||12345||N
@@ -5,7 +5,7 @@
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.01"
#property version "1.02"
#include <Trade\Trade.mqh>
#include "../_united/MagicNumberHelpers.mqh"
@@ -28,6 +28,12 @@ input bool UseTrailingStop = true; // move SL behind bid/ask whi
input double TrailingStopDistancePoints = 375.0; // SL distance from bid/ask (points)
input double TrailingActivationPoints = 75.0; // min profit before trailing (0 = same as distance)
input group "=== Session filter new entries (UTC) ==="
// Stocks/CFDs often shift behaviour around major cash opens; some NVDA 1h charts show a sharp volume + direction change near 09:00 UTC. Filter affects OPEN only (exits/trailing unchanged).
input bool UseSessionFilterUTC = false; // if true, block new entries outside [TradeStartHourUTC, TradeEndHourUTC)
input int TradeStartHourUTC = 9; // allow new trades when TimeGMT hour >= this (0..23)
input int TradeEndHourUTC = 22; // allow new trades when TimeGMT hour < this (exclusive). If Start>End, window wraps midnight (e.g. 22..6)
//--- Global variables
CTrade trade;
int rsi_handle;
@@ -105,6 +111,34 @@ void OnTick()
CheckEntrySignals();
}
//+------------------------------------------------------------------+
//| New entries allowed in [TradeStartHourUTC, TradeEndHourUTC) GMT |
//+------------------------------------------------------------------+
bool IsWithinNewEntryWindowUTC()
{
if(!UseSessionFilterUTC)
return true;
int s = TradeStartHourUTC;
int e = TradeEndHourUTC;
if(s < 0) s = 0;
if(s > 23) s = 23;
if(e < 0) e = 0;
if(e > 24) e = 24;
MqlDateTime dt;
TimeToStruct(TimeGMT(), dt);
const int h = dt.hour;
if(s == e)
return true;
if(s < e)
return (h >= s && h < e);
return (h >= s || h < e);
}
//+------------------------------------------------------------------+
//| Update RSI values |
//+------------------------------------------------------------------+
@@ -305,6 +339,9 @@ void CheckExistingPosition()
//+------------------------------------------------------------------+
void CheckEntrySignals()
{
if(!IsWithinNewEntryWindowUTC())
return;
// Buy signal: RSI crosses from oversold to above oversold (checking the actual crossover)
if(rsi_two_bars_ago <= RSI_Oversold && rsi_prev > RSI_Oversold)
{
@@ -0,0 +1,35 @@
; saved on 2026.05.13
; genetic optimization set for EMASlopeDistanceCocktailXAUUSD/main.mq5
; load in MT5 Strategy Tester -> Inputs -> Load
; format: Parameter=Current||Start||Step||Stop||Optimize(Y/N)
;
; ENUM_TIMEFRAMES: M1=1 M5=5 M15=15 M30=30 H1=16385 H4=16388 D1=16408
; Timeframe fixed at H1 (16385); sweeping 0..49153 can pick invalid enum values.
;
; Ranges/steps match Desktop 123.set (2026.05.13); Y marks parameters included in genetic optimization.
; === EMA / trigger thresholds ===
EMA_Periode=50||50||1||500||Y
PreisSchwelle=700.0||70.0||70.0||7000.0||Y
SteigungSchwelle=25.0||2.5||2.5||250.0||Y
ÜberwachungTimeout=340||1||1||3400||Y
TrailingStop=370.0||37.0||37.0||3700.0||Y
LotGröße=0.07||0.007||0.007||0.7||Y
; === execution / data ===
MagicNumber=135790||135790||1||1357900||N
UseSpreadAdjustment=true||false||0||true||N
Timeframe=16385||16385||0||16385||N
UseBarData=true||false||0||true||N
; === crossover / profit management ===
MaxTradesPerCrossover=10||1||1||100||Y
ProfitCheckBars=15||1||1||150||Y
CloseUnprofitableTrades=true||false||0||true||N
; === weekly ADX filter ===
UseWeeklyADXFilter=true||false||0||true||N
WeeklyADXPeriod=15||1||1||150||Y
WeeklyADXMin=40.0||4.0||4.0||400.0||Y
WeeklyADXBarShift=2||1||1||20||Y
WeeklyADXUseDirection=true||false||0||true||N
@@ -8,24 +8,24 @@
#property version "1.00"
#include <Trade\Trade.mqh>
#include "../_united/MagicNumberHelpers.mqh"
//--- Eingabeparameter (Input Parameters) - Optimized Profitable Parameters
input int EMA_Periode = 50; // EMA Periode
input double PreisSchwelle = 700.0; // Preisbewegung Schwelle in Pips
input double SteigungSchwelle = 25.0; // EMA Steigung Schwelle in Pips
//--- Eingabeparameter (Input Parameters) — synced with Desktop 123.set (2026.05.13)
input int EMA_Periode = 85; // EMA Periode
input double PreisSchwelle = 350.0; // Preisbewegung Schwelle in Pips
input double SteigungSchwelle = 22.5; // EMA Steigung Schwelle in Pips
input int ÜberwachungTimeout = 340; // Überwachungszeit in Sekunden
input double TrailingStop = 370.0; // Gleitender Stop in Pips
input double TrailingStop = 74.0; // Gleitender Stop in Pips
input double LotGröße = 0.07; // Handelsvolumen
input int MagicNumber = 135790; // 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 = 10; // Maximale Trades pro Crossover-Ereignis
input int ProfitCheckBars = 15; // Bars bis zur Profit-Prüfung
input int MaxTradesPerCrossover = 48; // Maximale Trades pro Crossover-Ereignis
input int ProfitCheckBars = 78; // Bars bis zur Profit-Prüfung
input bool CloseUnprofitableTrades = true; // Unprofitable Trades nach X Bars schließen
input bool UseWeeklyADXFilter = true; // W1 ADX Trendfilter aktivieren
input int WeeklyADXPeriod = 15; // ADX-Periode auf W1
input double WeeklyADXMin = 40.0; // Minimaler ADX fuer Trendfreigabe
input int WeeklyADXBarShift = 2; // 1=letzte geschlossene W1-Kerze
input int WeeklyADXPeriod = 28; // ADX-Periode auf W1
input double WeeklyADXMin = 25.0; // Minimaler ADX fuer Trendfreigabe
input int WeeklyADXBarShift = 8; // 1=letzte geschlossene W1-Kerze
input bool WeeklyADXUseDirection = true; // +DI/-DI Richtung mitpruefen
//--- Globale Variablen (Global Variables)
@@ -1,347 +0,0 @@
//+------------------------------------------------------------------+
//| RSIConsolidation.mq5 |
//| Mean-reversion RSI for ranging markets; trend filters block runs |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025"
#property link "https://www.mql5.com"
#property version "1.00"
#include <Trade\Trade.mqh>
//--- Symbol (empty = chart symbol)
input group "=== Symbol & session ==="
input string InpSymbol = "";
input group "=== Timeframe & bar logic ==="
input ENUM_TIMEFRAMES SignalTF = PERIOD_M15;
input bool EntryOnNewBarOnly = true;
//--- Core: no trend / consolidation regime
input group "=== Regime: consolidation (anti-trend) ==="
input int ADX_Period = 23;
input double ADX_Max = 29.0;
input bool UseATRRatioFilter = true;
input int ATR_Period = 8;
input int ATR_SMA_Period = 35;
input double ATR_Ratio_Max = 1.36;
input bool UseFlatEMAFilter = true;
input int EMA_Fast = 13;
input int EMA_Slow = 17;
input double EMA_Separation_MaxPct = 0.26;
//--- RSI entries (fade extremes toward mean)
input group "=== RSI entries ==="
input int RSI_Period = 8;
input ENUM_APPLIED_PRICE RSI_Price = PRICE_OPEN;
input double RSI_Oversold = 22.0;
input double RSI_Overbought = 63.0;
//--- Exits: mean target + hard ATR bracket
input group "=== Exits ==="
input bool UseRSI_MeanExit = true;
input double RSI_Exit_Long = 48.0;
input double RSI_Exit_Short = 52.0;
input double SL_ATR_Mult = 2.15;
input double TP_ATR_Mult = 2.40;
input int MaxBarsInTrade = 54;
input group "=== Risk & execution ==="
input double Lots = 0.10;
input ulong MagicNumber = 20250420;
input int Slippage = 10;
input int MaxSpreadPoints = 28;
CTrade trade;
string g_sym;
int h_rsi = INVALID_HANDLE;
int h_adx = INVALID_HANDLE;
int h_atr = INVALID_HANDLE;
int h_ema_fast = INVALID_HANDLE;
int h_ema_slow = INVALID_HANDLE;
datetime g_last_bar = 0;
bool PositionExistsByMagicSym(string sym, ulong magic)
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong t = PositionGetTicket(i);
if(t == 0) continue;
if(PositionGetString(POSITION_SYMBOL) == sym && PositionGetInteger(POSITION_MAGIC) == (long)magic)
return true;
}
return false;
}
ulong GetPositionTicketByMagicSym(string sym, ulong magic)
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong t = PositionGetTicket(i);
if(t == 0) continue;
if(PositionGetString(POSITION_SYMBOL) == sym && PositionGetInteger(POSITION_MAGIC) == (long)magic)
return t;
}
return 0;
}
bool SelectPositionTicketSymMagic(ulong ticket, string sym, ulong magic)
{
if(!PositionSelectByTicket(ticket)) return false;
return PositionGetString(POSITION_SYMBOL) == sym && PositionGetInteger(POSITION_MAGIC) == (long)magic;
}
double NormalizeVolume(string sym, double vol)
{
double minLot = SymbolInfoDouble(sym, SYMBOL_VOLUME_MIN);
double maxLot = SymbolInfoDouble(sym, SYMBOL_VOLUME_MAX);
double step = SymbolInfoDouble(sym, SYMBOL_VOLUME_STEP);
if(step > 0.0)
vol = MathFloor(vol / step) * step;
if(vol < minLot) vol = minLot;
if(vol > maxLot) vol = maxLot;
return vol;
}
int CurrentSpreadPoints(string sym)
{
long spread = 0;
if(!SymbolInfoInteger(sym, SYMBOL_SPREAD, spread))
return 999999;
return (int)spread;
}
double MinStopsDistancePrice(string sym)
{
long lvl = 0;
if(!SymbolInfoInteger(sym, SYMBOL_TRADE_STOPS_LEVEL, lvl))
return 0;
double pt = SymbolInfoDouble(sym, SYMBOL_POINT);
if(pt <= 0)
return 0;
return (double)lvl * pt;
}
bool Copy1(int handle, double &v)
{
double b[];
ArraySetAsSeries(b, true);
if(CopyBuffer(handle, 0, 0, 1, b) < 1) return false;
v = b[0];
return true;
}
bool RSI_Buffers(double &cur, double &prev, double &twoAgo)
{
double b[];
ArraySetAsSeries(b, true);
if(CopyBuffer(h_rsi, 0, 0, 3, b) < 3) return false;
cur = b[0];
prev = b[1];
twoAgo = b[2];
return true;
}
bool Regime_IsConsolidation()
{
double adx = 0;
if(!Copy1(h_adx, adx))
return false;
if(adx >= ADX_Max)
return false;
if(UseATRRatioFilter)
{
double atrArr[], atrSma[];
ArraySetAsSeries(atrArr, true);
if(CopyBuffer(h_atr, 0, 0, ATR_SMA_Period + 1, atrArr) < ATR_SMA_Period + 1)
return false;
double sum = 0;
for(int i = 1; i <= ATR_SMA_Period; i++)
sum += atrArr[i];
double smaAtr = sum / (double)ATR_SMA_Period;
if(smaAtr <= 0.0)
return false;
double ratio = atrArr[0] / smaAtr;
if(ratio > ATR_Ratio_Max)
return false;
}
if(UseFlatEMAFilter)
{
double ef[], es[];
ArraySetAsSeries(ef, true);
ArraySetAsSeries(es, true);
if(CopyBuffer(h_ema_fast, 0, 0, 1, ef) < 1) return false;
if(CopyBuffer(h_ema_slow, 0, 0, 1, es) < 1) return false;
double c = SymbolInfoDouble(g_sym, SYMBOL_BID);
if(c <= 0) return false;
double sep = MathAbs(ef[0] - es[0]) / c * 100.0;
if(sep > EMA_Separation_MaxPct)
return false;
}
return true;
}
bool Entry_BuyCross(double twoAgo, double prev)
{
return (twoAgo <= RSI_Oversold && prev > RSI_Oversold);
}
bool Entry_SellCross(double twoAgo, double prev)
{
return (twoAgo >= RSI_Overbought && prev < RSI_Overbought);
}
void TryCloseByRSI(ENUM_POSITION_TYPE typ, double rsi)
{
ulong tk = GetPositionTicketByMagicSym(g_sym, MagicNumber);
if(tk == 0 || !SelectPositionTicketSymMagic(tk, g_sym, MagicNumber))
return;
if(!UseRSI_MeanExit)
return;
if(typ == POSITION_TYPE_BUY && rsi >= RSI_Exit_Long)
trade.PositionClose(tk);
else if(typ == POSITION_TYPE_SELL && rsi <= RSI_Exit_Short)
trade.PositionClose(tk);
}
void ManageOpenPosition(double rsi)
{
ulong tk = GetPositionTicketByMagicSym(g_sym, MagicNumber);
if(tk == 0 || !SelectPositionTicketSymMagic(tk, g_sym, MagicNumber))
return;
ENUM_POSITION_TYPE typ = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
datetime openT = (datetime)PositionGetInteger(POSITION_TIME);
int barsAgo = iBarShift(g_sym, SignalTF, openT, false);
if(barsAgo >= 0 && barsAgo >= MaxBarsInTrade)
{
trade.PositionClose(tk);
return;
}
TryCloseByRSI(typ, rsi);
}
int OnInit()
{
g_sym = InpSymbol;
StringTrimLeft(g_sym);
StringTrimRight(g_sym);
if(StringLen(g_sym) == 0)
g_sym = _Symbol;
if(!SymbolSelect(g_sym, true))
{
Print("RSIConsolidation: SymbolSelect failed: ", g_sym);
return INIT_FAILED;
}
trade.SetExpertMagicNumber(MagicNumber);
trade.SetDeviationInPoints(Slippage);
trade.SetTypeFilling(ORDER_FILLING_RETURN);
h_rsi = iRSI(g_sym, SignalTF, RSI_Period, RSI_Price);
h_adx = iADX(g_sym, SignalTF, ADX_Period);
h_atr = iATR(g_sym, SignalTF, ATR_Period);
h_ema_fast = iMA(g_sym, SignalTF, EMA_Fast, 0, MODE_EMA, PRICE_CLOSE);
h_ema_slow = iMA(g_sym, SignalTF, EMA_Slow, 0, MODE_EMA, PRICE_CLOSE);
if(h_rsi == INVALID_HANDLE || h_adx == INVALID_HANDLE || h_atr == INVALID_HANDLE
|| h_ema_fast == INVALID_HANDLE || h_ema_slow == INVALID_HANDLE)
{
Print("RSIConsolidation: indicator init failed");
return INIT_FAILED;
}
Print("RSIConsolidation: symbol=", g_sym, " TF=", EnumToString(SignalTF));
return INIT_SUCCEEDED;
}
void OnDeinit(const int reason)
{
if(h_rsi != INVALID_HANDLE) IndicatorRelease(h_rsi);
if(h_adx != INVALID_HANDLE) IndicatorRelease(h_adx);
if(h_atr != INVALID_HANDLE) IndicatorRelease(h_atr);
if(h_ema_fast != INVALID_HANDLE) IndicatorRelease(h_ema_fast);
if(h_ema_slow != INVALID_HANDLE) IndicatorRelease(h_ema_slow);
}
bool EnoughHistory()
{
int need = MathMax(RSI_Period + 3, MathMax(ADX_Period + 2, ATR_SMA_Period + 3));
if(Bars(g_sym, SignalTF) < need)
return false;
return true;
}
void OnTick()
{
if(!EnoughHistory())
return;
if(MaxSpreadPoints > 0 && CurrentSpreadPoints(g_sym) > MaxSpreadPoints)
return;
double rsi, rsiPrev, rsi2;
if(!RSI_Buffers(rsi, rsiPrev, rsi2))
return;
datetime barTime = iTime(g_sym, SignalTF, 0);
bool isNew = (barTime != g_last_bar);
if(PositionExistsByMagicSym(g_sym, MagicNumber))
{
ManageOpenPosition(rsi);
if(isNew)
g_last_bar = barTime;
return;
}
if(EntryOnNewBarOnly && !isNew)
return;
g_last_bar = barTime;
if(!Regime_IsConsolidation())
return;
double atrArr[];
ArraySetAsSeries(atrArr, true);
if(CopyBuffer(h_atr, 0, 0, 1, atrArr) < 1)
return;
double atr = atrArr[0];
int dig = (int)SymbolInfoInteger(g_sym, SYMBOL_DIGITS);
double slDist = atr * SL_ATR_Mult;
double tpDist = atr * TP_ATR_Mult;
double minD = MinStopsDistancePrice(g_sym);
if(slDist < minD)
slDist = minD;
if(tpDist < minD)
tpDist = minD;
double vol = NormalizeVolume(g_sym, Lots);
if(Entry_BuyCross(rsi2, rsiPrev))
{
double ask = SymbolInfoDouble(g_sym, SYMBOL_ASK);
double sl = ask - slDist;
double tp = ask + tpDist;
sl = NormalizeDouble(sl, dig);
tp = NormalizeDouble(tp, dig);
trade.Buy(vol, g_sym, ask, sl, tp, "RSIConsolidation BUY");
}
else if(Entry_SellCross(rsi2, rsiPrev))
{
double bid = SymbolInfoDouble(g_sym, SYMBOL_BID);
double sl = bid + slDist;
double tp = bid - tpDist;
sl = NormalizeDouble(sl, dig);
tp = NormalizeDouble(tp, dig);
trade.Sell(vol, g_sym, bid, sl, tp, "RSIConsolidation SELL");
}
}
//+------------------------------------------------------------------+
@@ -1,37 +0,0 @@
; RSIConsolidation.mq5 — optimization preset (Strategy Tester → Inputs → Load)
; Format: Name=Current||Start||Step||Stop||Y|N (Y = include in optimization)
;
; === Symbol & session ===
InpSymbol=
; === Timeframe & bar logic ===
; SignalTF: optimize per run (ENUM is non-sequential); M15=15, H1=16385, H4=16388
SignalTF=15||15||0||15||N
EntryOnNewBarOnly=true||false||0||true||N
; === Regime: consolidation (anti-trend) ===
ADX_Period=14||7||1||28||Y
ADX_Max=22.0||16.0||1.0||32.0||Y
UseATRRatioFilter=true||false||0||true||N
ATR_Period=14||7||1||21||Y
ATR_SMA_Period=50||20||5||100||Y
ATR_Ratio_Max=1.18||1.0||0.02||1.35||Y
UseFlatEMAFilter=true||false||0||true||N
EMA_Fast=8||5||1||13||Y
EMA_Slow=21||13||2||34||Y
EMA_Separation_MaxPct=0.22||0.08||0.02||0.45||Y
; === RSI entries ===
RSI_Period=14||7||1||21||Y
RSI_Price=1||1||1||7||Y
RSI_Oversold=32.0||22.0||1.0||42.0||Y
RSI_Overbought=68.0||58.0||1.0||78.0||Y
; === Exits ===
UseRSI_MeanExit=true||false||0||true||N
RSI_Exit_Long=52.0||48.0||1.0||62.0||Y
RSI_Exit_Short=48.0||38.0||1.0||52.0||Y
SL_ATR_Mult=1.35||0.9||0.05||2.2||Y
TP_ATR_Mult=1.85||1.0||0.05||3.0||Y
MaxBarsInTrade=36||12||2||80||Y
; === Risk & execution ===
Lots=0.1||0.1||0.01||1.0||N
MagicNumber=20250420||20250420||1||20250420||N
Slippage=10||10||1||100||N
MaxSpreadPoints=0||0||1||30||Y
@@ -0,0 +1,38 @@
; RSICrossOverReversalXAUUSD/main.mq5 — Strategy Tester → Inputs → Load
;
; MT5 line format: Name=Value||From||Step||To||Optimize
; Value = input default when you Load this file
; From, Step, To = optimization range when Optimize=Y (Genetic / slow complete algorithm)
; Optimize=N = keep Value; From/Step/To are ignored
;
; First column matches main.mq5 source defaults (not the old Desktop 123 snapshot).
MagicNumber=7||7||1||7||N
rsiPeriod=19||10||1||35||Y
overboughtLevel=93||65||2||95||Y
oversoldLevel=22||10||1||45||Y
entryRSIBuySpread=0.0||0.0||0.5||8.0||Y
entryRSISellSpread=0.0||0.0||0.5||8.0||Y
lotSize=0.1||0.1||0.01||0.5||N
slippage=3||3||1||3||N
cooldownSeconds=209||60||30||600||Y
TimeFrame1=1||1||0||1||N
TimeFrame2=1||1||0||1||N
BarTimeFrame=12||12||0||12||N
emaPeriod=140||50||10||300||Y
emaSlopeThreshold=105.0||20.0||5.0||200.0||Y
exitBuyRSI=86.0||65.0||1.0||92.0||Y
exitSellRSI=10.0||5.0||1.0||40.0||Y
TrailingStop=295.0||80.0||15.0||450.0||Y
emaDistanceThreshold=165.0||40.0||10.0||350.0||Y
tradingHourOneBegin=24||0||1||23||N
tradingHourOneEnd=22||0||1||23||N
tradingHourTwoBegin=6||0||1||14||Y
tradingHourTwoEnd=19||14||1||23||Y
Sunday=false||false||0||true||Y
Monday=false||false||0||true||Y
Tuesday=true||false||0||true||Y
Wednesday=true||false||0||true||Y
Thursday=true||false||0||true||Y
Friday=false||false||0||true||Y
Saturday=false||false||0||true||Y
@@ -0,0 +1,50 @@
; RSIMidPointHijackXAUUSD/main.mq5 — Strategy Tester → Inputs → Load (Genetic optimization)
; Format: Parameter=Current||Start||Step||Stop||Optimize(Y/N)
;
; Baseline from Desktop 123.set (2026.05.13). InpTimeframe fixed at H1 (16385) to avoid invalid ENUM_TIMEFRAMES.
; RSI level sweeps capped at 100; hour sweeps capped at 23 (123.set used wider columns that are invalid for this EA).
; === General Settings ===
InpTimeframe=16385||16385||1||16385||N
InpLotSize=0.1||0.01||0.01||1.0||Y
InpMagicNumberRSIFollow=1001||1001||1||10010||N
InpMagicNumberRSIReverse=1002||1002||1||10020||N
InpMagicNumberEMACross=1003||1003||1||10030||N
; === Strategy Switches ===
InpEnableRSIFollow=true||false||0||true||N
InpEnableRSIReverse=true||false||0||true||N
InpEnableEMACross=true||false||0||true||N
InpEnableStrategyLock=true||false||0||true||N
InpLockProfitThreshold=6.0||0.6||0.6||60.0||Y
InpCloseOppositeTrades=true||false||0||true||N
; === RSI Follow Strategy ===
InpRSIPeriod=32||8||2||96||Y
InpRSIOverbought=78||60||1||95||Y
InpRSIOversold=46||5||1||45||Y
InpRSIExitLevel=44||10||1||90||Y
InpRSIFollowStartHour=23||0||1||23||Y
InpRSIFollowEndHour=8||0||1||23||Y
InpRSIFollowCloseOutsideHours=false||false||0||true||N
; === RSI Reverse Strategy ===
InpRSIReversePeriod=59||14||2||96||Y
InpRSIReverseOverbought=51||55||1||95||Y
InpRSIReverseOversold=49||5||1||50||Y
InpRSIReverseCrossLevel=53||45||1||70||Y
InpRSIReverseExitLevel=48||10||1||90||Y
InpRSIReverseStartHour=7||0||1||23||Y
InpRSIReverseEndHour=13||0||1||23||Y
InpRSIReverseCloseOutsideHours=false||false||0||true||N
InpRSIReverseCooldownBars=15||1||1||150||Y
InpRSIReverseCooldownOnLoss=true||false||0||true||N
; === EMA Cross Strategy ===
InpEMAPeriod=120||20||5||200||Y
InpEMACrossStartHour=8||0||1||23||Y
InpEMACrossEndHour=14||0||1||23||Y
InpEMACrossCloseOutsideHours=true||false||0||true||N
InpUseEMADistanceEntry=true||false||0||true||N
InpEMADistancePips=160.0||16.0||16.0||1600.0||Y
InpEMADistancePeriod=26||5||1||60||Y
@@ -0,0 +1,23 @@
; RSIReversalAsianAUDUSD/main.mq5 — Strategy Tester → Inputs → Load (Genetic optimization)
; Format: Parameter=Current||Start||Step||Stop||Optimize(Y/N)
; Baseline aligned with current input defaults and Desktop 123.set-style ranges (2026.05.13).
;
; Core RSI / exits
RSIPeriod=28||14||2||40||Y
OverboughtLevel=68.0||55.0||1.0||80.0||Y
OversoldLevel=30.0||18.0||1.0||42.0||Y
TakeProfitPips=175||50||25||350||Y
StopLossPips=5||5||5||80||Y
MaxLotSize=0.2||0.01||0.01||0.2||N
MaxSpread=1000||200||100||2000||Y
MaxDuration=340||48||24||720||Y
UseStopLoss=false||false||0||true||N
UseTakeProfit=false||false||0||true||N
UseRSIExit=true||false||0||true||N
RSIExitLevel=48.0||40.0||1.0||55.0||Y
CloseOutsideSession=true||false||0||true||Y
; Panel (usually fixed; colors as in MT5 saved sets)
PanelBackground=0
PanelText=16777215
PanelX=10||10||1||100||N
PanelY=20||20||1||200||N
@@ -0,0 +1,23 @@
; RSIReversalAsianAUDUSD/main.mq5 — Strategy Tester → Inputs → Load (Genetic optimization)
; Format: Parameter=Current||Start||Step||Stop||Optimize(Y/N)
; Baseline aligned with current input defaults and Desktop 123.set-style ranges (2026.05.13).
;
; Core RSI / exits
RSIPeriod=28||14||2||40||Y
OverboughtLevel=68.0||55.0||1.0||80.0||Y
OversoldLevel=30.0||18.0||1.0||42.0||Y
TakeProfitPips=175||50||25||350||Y
StopLossPips=5||5||5||80||Y
MaxLotSize=0.2||0.01||0.01||0.2||N
MaxSpread=1000||200||100||2000||Y
MaxDuration=340||48||24||720||Y
UseStopLoss=false||false||0||true||N
UseTakeProfit=false||false||0||true||N
UseRSIExit=true||false||0||true||N
RSIExitLevel=48.0||40.0||1.0||55.0||Y
CloseOutsideSession=true||false||0||true||Y
; Panel (usually fixed; colors as in MT5 saved sets)
PanelBackground=0
PanelText=16777215
PanelX=10||10||1||100||N
PanelY=20||20||1||200||N
@@ -1,5 +1,5 @@
//+------------------------------------------------------------------+
//| SimpleRSIReversalAUDUSD.mq5 |
//| RSIReversalAsianGBPUSD.mq5 |
//| Copyright 2024, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
@@ -11,19 +11,19 @@
// Include trade class
#include <Trade\Trade.mqh>
// Input parameters
input int RSIPeriod = 28; // RSI period
input double OverboughtLevel = 68; // Overbought level
input double OversoldLevel = 30; // Oversold level
input int TakeProfitPips = 175; // Take profit in pips
input int StopLossPips = 5; // Stop loss in pips
// Input parameters (defaults synced from working 123.set 2026.05.13)
input int RSIPeriod = 32; // RSI period
input double OverboughtLevel = 80; // Overbought level
input double OversoldLevel = 37; // Oversold level
input int TakeProfitPips = 225; // Take profit in pips
input int StopLossPips = 45; // Stop loss in pips
input double MaxLotSize = 0.2; // Maximum lot size
input int MaxSpread = 1000; // Maximum allowed spread in pips
input int MaxDuration = 340; // Maximum trade duration in hours
input int MaxSpread = 1800; // Maximum allowed spread in pips
input int MaxDuration = 480; // Maximum trade duration in hours
input bool UseStopLoss = false; // Use stop loss
input bool UseTakeProfit = false; // Use take profit
input bool UseRSIExit = true; // Use RSI for exit
input double RSIExitLevel = 48; // RSI level to exit (50 = neutral)
input double RSIExitLevel = 43; // RSI level to exit (50 = neutral)
input bool CloseOutsideSession = true; // Close trades outside Asian session
input color PanelBackground = clrBlack; // Panel background color
input color PanelText = clrWhite; // Panel text color

Before

Width:  |  Height:  |  Size: 241 KiB

After

Width:  |  Height:  |  Size: 241 KiB

+327
View File
@@ -0,0 +1,327 @@
//+------------------------------------------------------------------+
//| RSIScalping.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"
#include <Trade\Trade.mqh>
#include "../_united/MagicNumberHelpers.mqh"
//--- Input parameters — synced with Desktop 123.set (2026.05.13)
input ENUM_TIMEFRAMES TimeFrame = PERIOD_M20; // Timeframe for Analysis
input int RSI_Period = 14; // RSI Period
input ENUM_APPLIED_PRICE RSI_Applied_Price = PRICE_CLOSE; // RSI Applied Price
input double RSI_Overbought = 32; // RSI Overbought Level
input double RSI_Oversold = 86; // RSI Oversold Level
input double RSI_Target_Buy = 100; // RSI Target for Buy Exit
input double RSI_Target_Sell = 24; // RSI Target for Sell Exit
input int BarsToWait = 34; // Bars to wait when RSI goes against position
input double LotSize = 5; // Lot Size
input int MagicNumber = 129102315; // Magic Number
input int Slippage = 3; // Slippage in points
//--- Global variables
CTrade trade;
int rsi_handle;
double rsi_buffer[];
double rsi_prev, rsi_current, rsi_two_bars_ago;
bool position_open = false;
int position_ticket = 0;
ENUM_POSITION_TYPE current_position_type = POSITION_TYPE_BUY;
datetime last_bar_time = 0;
bool rsi_against_position = false;
int bars_against_count = 0;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Initialize RSI indicator
rsi_handle = iRSI(_Symbol, TimeFrame, RSI_Period, RSI_Applied_Price);
if(rsi_handle == INVALID_HANDLE)
{
return(INIT_FAILED);
}
// Initialize trade object
trade.SetExpertMagicNumber(MagicNumber);
trade.SetDeviationInPoints(Slippage);
trade.SetTypeFilling(ORDER_FILLING_FOK);
// Allocate arrays
ArraySetAsSeries(rsi_buffer, true);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if(rsi_handle != INVALID_HANDLE)
IndicatorRelease(rsi_handle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// Check if we have enough bars
if(Bars(_Symbol, TimeFrame) < RSI_Period + 2)
{
return;
}
// Check if this is a new bar
datetime current_bar_time = iTime(_Symbol, TimeFrame, 0);
if(current_bar_time == last_bar_time)
{
return; // Still the same bar, don't process
}
last_bar_time = current_bar_time;
// Update RSI values
if(!UpdateRSI())
{
return;
}
// Check for existing position
CheckExistingPosition();
// 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();
}
}
//+------------------------------------------------------------------+
//| Update RSI values |
//+------------------------------------------------------------------+
bool UpdateRSI()
{
if(CopyBuffer(rsi_handle, 0, 0, 3, rsi_buffer) < 3)
{
return false;
}
rsi_current = rsi_buffer[0]; // Current bar
rsi_prev = rsi_buffer[1]; // Previous bar
rsi_two_bars_ago = rsi_buffer[2]; // Two bars ago
return true;
}
//+------------------------------------------------------------------+
//| Check existing position for exit conditions |
//+------------------------------------------------------------------+
void CheckExistingPosition()
{
if(!position_open)
{
return;
}
// 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;
rsi_against_position = false;
bars_against_count = 0;
return;
}
// Exit conditions based on RSI target
if(current_position_type == POSITION_TYPE_BUY)
{
// Check if RSI is against the position (below oversold)
if(rsi_current < RSI_Oversold)
{
if(!rsi_against_position)
{
rsi_against_position = true;
bars_against_count = 1;
}
else
{
bars_against_count++;
}
// Close position if RSI has been against for Y bars
if(bars_against_count >= BarsToWait)
{
ClosePosition();
return;
}
}
else
{
// RSI is no longer against the position, reset counter
if(rsi_against_position)
{
rsi_against_position = false;
bars_against_count = 0;
}
// Exit long position when RSI reaches buy target
if(rsi_current >= RSI_Target_Buy)
{
ClosePosition();
}
}
}
else if(current_position_type == POSITION_TYPE_SELL)
{
// Check if RSI is against the position (above overbought)
if(rsi_current > RSI_Overbought)
{
if(!rsi_against_position)
{
rsi_against_position = true;
bars_against_count = 1;
}
else
{
bars_against_count++;
}
// Close position if RSI has been against for Y bars
if(bars_against_count >= BarsToWait)
{
ClosePosition();
return;
}
}
else
{
// RSI is no longer against the position, reset counter
if(rsi_against_position)
{
rsi_against_position = false;
bars_against_count = 0;
}
// Exit short position when RSI reaches sell target
if(rsi_current <= RSI_Target_Sell)
{
ClosePosition();
}
}
}
}
//+------------------------------------------------------------------+
//| Check for entry signals |
//+------------------------------------------------------------------+
void CheckEntrySignals()
{
// Buy signal: RSI crosses from oversold to above oversold (checking the actual crossover)
if(rsi_two_bars_ago <= RSI_Oversold && rsi_prev > RSI_Oversold)
{
OpenBuyPosition();
}
// Sell signal: RSI crosses from overbought to below overbought (checking the actual crossover)
if(rsi_two_bars_ago >= RSI_Overbought && rsi_prev < RSI_Overbought)
{
OpenSellPosition();
}
}
//+------------------------------------------------------------------+
//| Open buy position |
//+------------------------------------------------------------------+
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"))
{
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");
}
}
}
}
//+------------------------------------------------------------------+
//| Open sell position |
//+------------------------------------------------------------------+
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"))
{
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");
}
}
}
}
//+------------------------------------------------------------------+
//| Close current position |
//+------------------------------------------------------------------+
void ClosePosition()
{
// 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;
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

+10 -10
View File
@@ -10,17 +10,17 @@
#include <Trade\Trade.mqh>
#include "../_united/MagicNumberHelpers.mqh"
//--- Input parameters
input ENUM_TIMEFRAMES TimeFrame = PERIOD_M15; // Timeframe for Analysis
input int RSI_Period = 8; // RSI Period
//--- Input parameters — synced with Desktop 123.set (2026.05.13)
input ENUM_TIMEFRAMES TimeFrame = PERIOD_M20; // Timeframe for Analysis
input int RSI_Period = 14; // RSI Period
input ENUM_APPLIED_PRICE RSI_Applied_Price = PRICE_CLOSE; // RSI Applied Price
input double RSI_Overbought = 36; // RSI Overbought Level
input double RSI_Oversold = 38; // RSI Oversold Level
input double RSI_Target_Buy = 90; // RSI Target for Buy Exit
input double RSI_Target_Sell = 70; // RSI Target for Sell Exit
input int BarsToWait = 5; // Bars to wait when RSI goes against position
input double LotSize = 50; // Lot Size
input int MagicNumber = 12345; // Magic Number
input double RSI_Overbought = 6; // RSI Overbought Level
input double RSI_Oversold = 66; // RSI Oversold Level
input double RSI_Target_Buy = 98; // RSI Target for Buy Exit
input double RSI_Target_Sell = 52; // RSI Target for Sell Exit
input int BarsToWait = 12; // Bars to wait when RSI goes against position
input double LotSize = 5; // Lot Size
input int MagicNumber = 129102315; // Magic Number
input int Slippage = 3; // Slippage in points
//--- Global variables
+9 -9
View File
@@ -10,17 +10,17 @@
#include <Trade\Trade.mqh>
#include "../_united/MagicNumberHelpers.mqh"
//--- Input parameters
input ENUM_TIMEFRAMES TimeFrame = PERIOD_H1; // Timeframe for Analysis
//--- Input parameters — synced with Desktop 123.set (2026.05.13)
input ENUM_TIMEFRAMES TimeFrame = PERIOD_M20; // Timeframe for Analysis
input int RSI_Period = 14; // RSI Period
input ENUM_APPLIED_PRICE RSI_Applied_Price = PRICE_CLOSE; // RSI Applied Price
input double RSI_Overbought = 54; // RSI Overbought Level
input double RSI_Oversold = 73; // RSI Oversold Level
input double RSI_Target_Buy = 87; // RSI Target for Buy Exit
input double RSI_Target_Sell = 33; // RSI Target for Sell Exit
input int BarsToWait = 1; // Bars to wait when RSI goes against position
input double LotSize = 50; // Lot Size
input int MagicNumber = 125421321; // Magic Number
input double RSI_Overbought = 32; // RSI Overbought Level
input double RSI_Oversold = 86; // RSI Oversold Level
input double RSI_Target_Buy = 100; // RSI Target for Buy Exit
input double RSI_Target_Sell = 24; // RSI Target for Sell Exit
input int BarsToWait = 34; // Bars to wait when RSI goes against position
input double LotSize = 5; // Lot Size
input int MagicNumber = 129102315; // Magic Number
input int Slippage = 3; // Slippage in points
//--- Global variables
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

@@ -1,36 +0,0 @@
; SuperEMA — defaults aligned with lab/EAs/SuperEMA.mq5 (v1.01)
; Load from Strategy Tester → Inputs → context menu → Load
;
; === Market ===
InpSymbol=
InpTimeframe=15||15||0||49153||N
InpLots=0.01||0.01||0.01||0.10||N
InpSlippagePoints=55||20||5||120||Y
InpMagic=940001||940001||1||9400010||N
; === EMA (trend & structure) ===
InpEmaFast=40||20||10||120||Y
InpEmaMid=180||60||15||200||Y
InpEmaSlow=125||100||25||400||Y
InpEmaTrendBars=3||1||1||3||Y
; === CCI ===
InpCciPeriod=17||7||1||28||Y
InpCciOverbought=80.0||80.0||10.0||140.0||Y
InpCciOversold=-140.0||-140.0||10.0||-80.0||Y
InpPullbackCciLookback=20||4||2||24||Y
; === MACD (histogram = main - signal) ===
InpMacdFast=14||8||2||20||Y
InpMacdSlow=38||20||2||40||Y
InpMacdSignal=9||5||1||15||Y
; === Strategy ===
InpEntryStyle=1||0||1||2||Y
InpOneTradeOnly=true||false||0||true||N
InpUseStructuralSL=false||false||0||true||Y
InpSlBufferPoints=110.0||20.0||10.0||200.0||Y
; === Exits (so trades do not run forever) ===
InpExitOnTrendFlip=false||false||0||true||Y
InpExitOnMacdFlip=false||false||0||true||Y
InpExitOnCciZeroCross=true||false||0||true||Y
InpMaxHoldingBars=168||48||24||480||Y
InpExitBelowMidEma=false||false||0||true||Y
; === Debug ===
InpDebugLogs=false||false||0||true||N
-448
View File
@@ -1,448 +0,0 @@
//+------------------------------------------------------------------+
//| SuperEMA.mq5 |
//| EMA + CCI + MACD histogram — trend filter, momentum confirmation |
//+------------------------------------------------------------------+
#property strict
#property version "1.01"
#include <Trade/Trade.mqh>
enum ENUM_ENTRY_STYLE
{
ENTRY_CCIZERO_MACD = 0, // EMA trend + CCI crosses zero + MACD histogram agrees
ENTRY_LAMBERT = 1, // EMA trend + CCI crosses ±100 + MACD histogram agrees
ENTRY_PULLBACK = 2 // Uptrend: pullback to fast EMA + CCI was oversold + CCI crosses up through 0 + MACD > 0 (mirror for sells)
};
input group "=== Market ==="
input string InpSymbol = "";
input ENUM_TIMEFRAMES InpTimeframe = PERIOD_M15;
input double InpLots = 0.01;
input int InpSlippagePoints = 55;
input int InpMagic = 940001;
input group "=== EMA (trend & structure) ==="
input int InpEmaFast = 40;
input int InpEmaMid = 180;
input int InpEmaSlow = 125;
input int InpEmaTrendBars = 3; // closed bar shift for EMA reads
input group "=== CCI ==="
input int InpCciPeriod = 17;
input double InpCciOverbought = 80.0;
input double InpCciOversold = -140.0;
input int InpPullbackCciLookback = 20; // bars to check prior CCI oversold/overbought
input group "=== MACD (histogram = main - signal) ==="
input int InpMacdFast = 14;
input int InpMacdSlow = 38;
input int InpMacdSignal = 9;
input group "=== Strategy ==="
input ENUM_ENTRY_STYLE InpEntryStyle = ENTRY_LAMBERT;
input bool InpOneTradeOnly = true;
input bool InpUseStructuralSL = false;
input double InpSlBufferPoints = 110;
input group "=== Exits (so trades do not run forever) ==="
input bool InpExitOnTrendFlip = false; // close when price vs slow EMA flips against position
input bool InpExitOnMacdFlip = false; // close when MACD histogram flips against position
input bool InpExitOnCciZeroCross = true; // long: CCI crosses below 0; short: CCI crosses above 0
input int InpMaxHoldingBars = 168; // 0 = disabled (e.g. ~8 days M15)
input bool InpExitBelowMidEma = false; // long: close if close < mid EMA (invalidation)
input group "=== Debug ==="
input bool InpDebugLogs = false;
CTrade trade;
datetime g_lastBarTime = 0;
string WorkSymbol()
{
return (InpSymbol == "" || InpSymbol == NULL) ? _Symbol : InpSymbol;
}
void Log(const string s)
{
if(InpDebugLogs)
Print("[SuperEMA] ", s);
}
bool IsNewBar(const string sym, const ENUM_TIMEFRAMES tf)
{
datetime t = iTime(sym, tf, 0);
if(t <= 0 || t == g_lastBarTime)
return false;
g_lastBarTime = t;
return true;
}
double EmaAt(const string sym, const ENUM_TIMEFRAMES tf, const int period, const int shift)
{
int h = iMA(sym, tf, period, 0, MODE_EMA, PRICE_CLOSE);
if(h == INVALID_HANDLE)
return 0.0;
double b[1];
if(CopyBuffer(h, 0, shift, 1, b) <= 0)
{
IndicatorRelease(h);
return 0.0;
}
IndicatorRelease(h);
return b[0];
}
double CciAt(const string sym, const ENUM_TIMEFRAMES tf, const int period, const int shift)
{
int h = iCCI(sym, tf, period, PRICE_TYPICAL);
if(h == INVALID_HANDLE)
return 0.0;
double b[1];
if(CopyBuffer(h, 0, shift, 1, b) <= 0)
{
IndicatorRelease(h);
return 0.0;
}
IndicatorRelease(h);
return b[0];
}
bool MacdHistAt(const string sym, const ENUM_TIMEFRAMES tf, const int fast, const int slow, const int signal, const int shift, double &hist)
{
int h = iMACD(sym, tf, fast, slow, signal, PRICE_CLOSE);
if(h == INVALID_HANDLE)
return false;
double mainLine[1], sigLine[1];
if(CopyBuffer(h, 0, shift, 1, mainLine) <= 0 || CopyBuffer(h, 1, shift, 1, sigLine) <= 0)
{
IndicatorRelease(h);
return false;
}
IndicatorRelease(h);
hist = mainLine[0] - sigLine[0];
return true;
}
bool TrendUp(const string sym, const int sh)
{
double c = iClose(sym, InpTimeframe, sh);
double emaS = EmaAt(sym, InpTimeframe, InpEmaSlow, sh);
return (emaS > 0.0 && c > emaS);
}
bool TrendDown(const string sym, const int sh)
{
double c = iClose(sym, InpTimeframe, sh);
double emaS = EmaAt(sym, InpTimeframe, InpEmaSlow, sh);
return (emaS > 0.0 && c < emaS);
}
bool CciCrossAboveZero(const string sym)
{
double c1 = CciAt(sym, InpTimeframe, InpCciPeriod, 1);
double c2 = CciAt(sym, InpTimeframe, InpCciPeriod, 2);
return (c2 <= 0.0 && c1 > 0.0);
}
bool CciCrossBelowZero(const string sym)
{
double c1 = CciAt(sym, InpTimeframe, InpCciPeriod, 1);
double c2 = CciAt(sym, InpTimeframe, InpCciPeriod, 2);
return (c2 >= 0.0 && c1 < 0.0);
}
bool CciCrossAbove100(const string sym)
{
double c1 = CciAt(sym, InpTimeframe, InpCciPeriod, 1);
double c2 = CciAt(sym, InpTimeframe, InpCciPeriod, 2);
return (c2 < InpCciOverbought && c1 > InpCciOverbought);
}
bool CciCrossBelowMinus100(const string sym)
{
double c1 = CciAt(sym, InpTimeframe, InpCciPeriod, 1);
double c2 = CciAt(sym, InpTimeframe, InpCciPeriod, 2);
return (c2 > InpCciOversold && c1 < InpCciOversold);
}
bool HadCciOversoldRecently(const string sym)
{
for(int i = 2; i <= InpPullbackCciLookback + 1; i++)
{
double v = CciAt(sym, InpTimeframe, InpCciPeriod, i);
if(v <= InpCciOversold)
return true;
}
return false;
}
bool HadCciOverboughtRecently(const string sym)
{
for(int i = 2; i <= InpPullbackCciLookback + 1; i++)
{
double v = CciAt(sym, InpTimeframe, InpCciPeriod, i);
if(v >= InpCciOverbought)
return true;
}
return false;
}
bool PullbackNearFastEmaLong(const string sym)
{
double emaF = EmaAt(sym, InpTimeframe, InpEmaFast, 1);
double lo = iLow(sym, InpTimeframe, 1);
if(emaF <= 0.0)
return false;
return (lo <= emaF + InpSlBufferPoints * _Point * 3.0);
}
bool PullbackNearFastEmaShort(const string sym)
{
double emaF = EmaAt(sym, InpTimeframe, InpEmaFast, 1);
double hi = iHigh(sym, InpTimeframe, 1);
if(emaF <= 0.0)
return false;
return (hi >= emaF - InpSlBufferPoints * _Point * 3.0);
}
int PositionsByMagic(const string sym, const int magic)
{
int n = 0;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong t = PositionGetTicket(i);
if(t == 0)
continue;
if(PositionGetString(POSITION_SYMBOL) == sym && (int)PositionGetInteger(POSITION_MAGIC) == magic)
n++;
}
return n;
}
void ComputeSLTP(const bool isBuy, const double entry, double &sl, double &tp)
{
const string sym = WorkSymbol();
sl = 0.0;
tp = 0.0;
if(!InpUseStructuralSL)
return;
double emaM = EmaAt(sym, InpTimeframe, InpEmaMid, InpEmaTrendBars);
double buf = InpSlBufferPoints * _Point;
if(isBuy)
sl = emaM - buf;
else
sl = emaM + buf;
}
int BarsSinceOpen(const string sym, const datetime openTime)
{
if(openTime <= 0)
return 0;
int sh = iBarShift(sym, InpTimeframe, openTime, false);
if(sh < 0)
return 999999;
return sh;
}
void ClosePositionTicket(const ulong ticket, const string reason)
{
trade.SetExpertMagicNumber(InpMagic);
if(trade.PositionClose(ticket))
Log("Close: " + reason);
}
void ManageSuperEMAExits(const string sym)
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket == 0)
continue;
if(!PositionSelectByTicket(ticket))
continue;
if(PositionGetString(POSITION_SYMBOL) != sym)
continue;
if((int)PositionGetInteger(POSITION_MAGIC) != InpMagic)
continue;
ENUM_POSITION_TYPE ptype = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
datetime openTime = (datetime)PositionGetInteger(POSITION_TIME);
double h1 = 0.0;
if(!MacdHistAt(sym, InpTimeframe, InpMacdFast, InpMacdSlow, InpMacdSignal, 1, h1))
continue;
bool closeLong = false;
bool closeShort = false;
string reason = "";
if(InpMaxHoldingBars > 0)
{
int held = BarsSinceOpen(sym, openTime);
if(held >= InpMaxHoldingBars)
{
if(ptype == POSITION_TYPE_BUY)
closeLong = true;
else
closeShort = true;
reason = "time stop (max bars)";
}
}
if(ptype == POSITION_TYPE_BUY)
{
if(InpExitOnTrendFlip && TrendDown(sym, InpEmaTrendBars))
{
closeLong = true;
reason = "trend flip (below slow EMA)";
}
if(InpExitOnMacdFlip && h1 < 0.0)
{
closeLong = true;
reason = "MACD histogram < 0";
}
if(InpExitOnCciZeroCross && CciCrossBelowZero(sym))
{
closeLong = true;
reason = "CCI crossed below zero";
}
if(InpExitBelowMidEma)
{
double c = iClose(sym, InpTimeframe, 1);
double emaM = EmaAt(sym, InpTimeframe, InpEmaMid, 1);
if(emaM > 0.0 && c < emaM)
{
closeLong = true;
reason = "close below mid EMA";
}
}
if(closeLong)
ClosePositionTicket(ticket, reason);
}
else if(ptype == POSITION_TYPE_SELL)
{
if(InpExitOnTrendFlip && TrendUp(sym, InpEmaTrendBars))
{
closeShort = true;
reason = "trend flip (above slow EMA)";
}
if(InpExitOnMacdFlip && h1 > 0.0)
{
closeShort = true;
reason = "MACD histogram > 0";
}
if(InpExitOnCciZeroCross && CciCrossAboveZero(sym))
{
closeShort = true;
reason = "CCI crossed above zero";
}
if(InpExitBelowMidEma)
{
double c = iClose(sym, InpTimeframe, 1);
double emaM = EmaAt(sym, InpTimeframe, InpEmaMid, 1);
if(emaM > 0.0 && c > emaM)
{
closeShort = true;
reason = "close above mid EMA";
}
}
if(closeShort)
ClosePositionTicket(ticket, reason);
}
}
}
int OnInit()
{
string sym = WorkSymbol();
if(!SymbolSelect(sym, true))
{
Print("SuperEMA: cannot select symbol ", sym);
return INIT_FAILED;
}
trade.SetExpertMagicNumber(InpMagic);
trade.SetDeviationInPoints(InpSlippagePoints);
return INIT_SUCCEEDED;
}
void OnTick()
{
string sym = WorkSymbol();
if(_Symbol != sym)
{
static datetime lastLog = 0;
datetime tb = iTime(_Symbol, PERIOD_M1, 0);
if(tb != lastLog && InpDebugLogs)
{
lastLog = tb;
Log("Chart symbol differs from WorkSymbol; attach to " + sym + " or set InpSymbol empty.");
}
return;
}
if(!IsNewBar(sym, InpTimeframe))
return;
// Exits must run every bar; do not skip when a position exists (otherwise trades never close with SL=0/TP=0).
ManageSuperEMAExits(sym);
if(InpOneTradeOnly && PositionsByMagic(sym, InpMagic) > 0)
return;
const int sh = InpEmaTrendBars;
double h1 = 0.0, h2 = 0.0;
if(!MacdHistAt(sym, InpTimeframe, InpMacdFast, InpMacdSlow, InpMacdSignal, 1, h1) ||
!MacdHistAt(sym, InpTimeframe, InpMacdFast, InpMacdSlow, InpMacdSignal, 2, h2))
return;
bool up = TrendUp(sym, sh);
bool dn = TrendDown(sym, sh);
bool wantBuy = false;
bool wantSell = false;
switch(InpEntryStyle)
{
case ENTRY_CCIZERO_MACD:
if(up && CciCrossAboveZero(sym) && h1 > 0.0)
wantBuy = true;
if(dn && CciCrossBelowZero(sym) && h1 < 0.0)
wantSell = true;
break;
case ENTRY_LAMBERT:
if(up && CciCrossAbove100(sym) && h1 > 0.0)
wantBuy = true;
if(dn && CciCrossBelowMinus100(sym) && h1 < 0.0)
wantSell = true;
break;
case ENTRY_PULLBACK:
if(up && HadCciOversoldRecently(sym) && CciCrossAboveZero(sym) && h1 > 0.0 && PullbackNearFastEmaLong(sym))
wantBuy = true;
if(dn && HadCciOverboughtRecently(sym) && CciCrossBelowZero(sym) && h1 < 0.0 && PullbackNearFastEmaShort(sym))
wantSell = true;
break;
}
MqlTick tick;
if(!SymbolInfoTick(sym, tick))
return;
double sl = 0.0, tp = 0.0;
if(wantBuy && !wantSell)
{
ComputeSLTP(true, tick.ask, sl, tp);
if(trade.Buy(InpLots, sym, tick.ask, sl, tp, "SuperEMA long"))
Log(StringFormat("BUY ask=%.5f sl=%.5f cci=%.2f macdHist=%.5f", tick.ask, sl,
CciAt(sym, InpTimeframe, InpCciPeriod, 1), h1));
}
else if(wantSell && !wantBuy)
{
ComputeSLTP(false, tick.bid, sl, tp);
if(trade.Sell(InpLots, sym, tick.bid, sl, tp, "SuperEMA short"))
Log(StringFormat("SELL bid=%.5f sl=%.5f cci=%.2f macdHist=%.5f", tick.bid, sl,
CciAt(sym, InpTimeframe, InpCciPeriod, 1), h1));
}
}
@@ -0,0 +1,26 @@
; CandleChartPattern/main.mq5 — Strategy Tester → Inputs → Load
; Format: Name=Value||From||Step||To||Optimize(Y/N)
; Value = load default (aligned with EA + Desktop 123.set 2026.05.14). From/Step/To used when Y.
;
; === Market ===
InpSymbol=
InpLots=0.01||0.01||0.01||0.2||N
InpMagic=771001||771001||1||771001||N
InpSlippagePoints=30||30||1||300||N
InpMaxSpreadPoints=50||10||5||200||Y
; === Timeframes ===
; Enum timeframes: keep fixed during optimization (change manually if needed).
InpSignalTF=15||0||0||49153||N
InpConfirmTF=16385||0||0||49153||N
; === Patterns (signal TF, shift 1) ===
InpUseEngulfing=true||false||0||true||Y
InpUseHammerPin=true||false||0||true||Y
InpMinBodyPoints=5.0||2.0||0.5||25.0||Y
InpHammerWickRatio=2.0||1.2||0.1||4.0||Y
; === HTF confirmation ===
InpRequireHtfCandleDir=true||false||0||true||Y
InpRequireHtfPattern=false||false||0||true||Y
; === Behaviour ===
InpOnlyOnePosition=true||false||0||true||N
InpCloseOnReverseSignal=true||false||0||true||Y
InpCloseOnAdversePattern=true||false||0||true||Y
+332
View File
@@ -0,0 +1,332 @@
//+------------------------------------------------------------------+
//| CandleChartPattern.mq5 |
//| Lab EA: candle patterns on signal TF + HTF confirmation. |
//| No SL/TP. Exit on opposite signal or adverse pattern. |
//+------------------------------------------------------------------+
#property copyright "Lab"
#property link ""
#property version "1.01"
#property strict
#include <Trade/Trade.mqh>
input group "=== Market ==="
input string InpSymbol = ""; // empty = chart symbol
input double InpLots = 0.01;
input int InpMagic = 771001;
input int InpSlippagePoints = 30;
input int InpMaxSpreadPoints = 50; // 0 = ignore
input group "=== Timeframes ==="
input ENUM_TIMEFRAMES InpSignalTF = PERIOD_M15; // patterns evaluated here (bar 1 = last closed)
input ENUM_TIMEFRAMES InpConfirmTF = PERIOD_H1; // must be >= InpSignalTF for stable bias (not enforced)
input group "=== Patterns (signal TF, shift 1) ==="
input bool InpUseEngulfing = true;
input bool InpUseHammerPin = true;
input double InpMinBodyPoints = 5.0; // min body size for engulfing (points)
input double InpHammerWickRatio = 2.0; // shadow >= ratio * body for hammer/pin
input group "=== HTF confirmation ==="
input bool InpRequireHtfCandleDir = true; // HTF last closed bar same direction as trade idea
input bool InpRequireHtfPattern = false; // if true, same pattern class must also print on HTF bar 1
input group "=== Behaviour ==="
input bool InpOnlyOnePosition = true;
input bool InpCloseOnReverseSignal = true; // close long if validated short setup appears (and vice versa)
input bool InpCloseOnAdversePattern = true; // close long on bearish engulf / bear pin on signal or HTF
CTrade g_trade;
string g_sym;
datetime g_lastSignalBarTime = 0;
ENUM_ORDER_TYPE_FILLING ResolveFilling(const string sym)
{
const long mask = SymbolInfoInteger(sym, SYMBOL_FILLING_MODE);
if((mask & SYMBOL_FILLING_IOC) == SYMBOL_FILLING_IOC)
return ORDER_FILLING_IOC;
if((mask & SYMBOL_FILLING_FOK) == SYMBOL_FILLING_FOK)
return ORDER_FILLING_FOK;
return ORDER_FILLING_RETURN;
}
bool SpreadOk(const string sym)
{
if(InpMaxSpreadPoints <= 0)
return true;
const double point = SymbolInfoDouble(sym, SYMBOL_POINT);
if(point <= 0.0)
return false;
const double spreadPts = (SymbolInfoDouble(sym, SYMBOL_ASK) - SymbolInfoDouble(sym, SYMBOL_BID)) / point;
return (spreadPts <= (double)InpMaxSpreadPoints);
}
bool IsNewSignalBar()
{
const datetime t = iTime(g_sym, InpSignalTF, 0);
if(t <= 0)
return false;
if(t == g_lastSignalBarTime)
return false;
g_lastSignalBarTime = t;
return true;
}
double BodyPoints(const string s, const ENUM_TIMEFRAMES tf, const int sh)
{
const double o = iOpen(s, tf, sh);
const double c = iClose(s, tf, sh);
const double point = SymbolInfoDouble(s, SYMBOL_POINT);
if(point <= 0.0)
return 0.0;
return MathAbs(c - o) / point;
}
bool BullishEngulfing(const string s, const ENUM_TIMEFRAMES tf, const int sh)
{
if(!InpUseEngulfing)
return false;
const double o1 = iOpen(s, tf, sh);
const double c1 = iClose(s, tf, sh);
const double o2 = iOpen(s, tf, sh + 1);
const double c2 = iClose(s, tf, sh + 1);
if(c2 >= o2)
return false;
if(c1 <= o1)
return false;
if(BodyPoints(s, tf, sh) < InpMinBodyPoints || BodyPoints(s, tf, sh + 1) < InpMinBodyPoints)
return false;
return (o1 <= c2 && c1 >= o2);
}
bool BearishEngulfing(const string s, const ENUM_TIMEFRAMES tf, const int sh)
{
if(!InpUseEngulfing)
return false;
const double o1 = iOpen(s, tf, sh);
const double c1 = iClose(s, tf, sh);
const double o2 = iOpen(s, tf, sh + 1);
const double c2 = iClose(s, tf, sh + 1);
if(c2 <= o2)
return false;
if(c1 >= o1)
return false;
if(BodyPoints(s, tf, sh) < InpMinBodyPoints || BodyPoints(s, tf, sh + 1) < InpMinBodyPoints)
return false;
return (o1 >= c2 && c1 <= o2);
}
bool BullishHammer(const string s, const ENUM_TIMEFRAMES tf, const int sh)
{
if(!InpUseHammerPin)
return false;
const double o = iOpen(s, tf, sh);
const double c = iClose(s, tf, sh);
const double h = iHigh(s, tf, sh);
const double l = iLow(s, tf, sh);
const double body = MathAbs(c - o);
const double lower = MathMin(o, c) - l;
const double upper = h - MathMax(o, c);
const double point = SymbolInfoDouble(s, SYMBOL_POINT);
if(point <= 0.0 || body < point * 0.1)
return false;
return (lower >= InpHammerWickRatio * body && upper <= body);
}
bool BearishPinBar(const string s, const ENUM_TIMEFRAMES tf, const int sh)
{
if(!InpUseHammerPin)
return false;
const double o = iOpen(s, tf, sh);
const double c = iClose(s, tf, sh);
const double h = iHigh(s, tf, sh);
const double l = iLow(s, tf, sh);
const double body = MathAbs(c - o);
const double lower = MathMin(o, c) - l;
const double upper = h - MathMax(o, c);
const double point = SymbolInfoDouble(s, SYMBOL_POINT);
if(point <= 0.0 || body < point * 0.1)
return false;
return (upper >= InpHammerWickRatio * body && lower <= body);
}
bool BullishPatternBar(const string s, const ENUM_TIMEFRAMES tf, const int sh)
{
return BullishEngulfing(s, tf, sh) || BullishHammer(s, tf, sh);
}
bool BearishPatternBar(const string s, const ENUM_TIMEFRAMES tf, const int sh)
{
return BearishEngulfing(s, tf, sh) || BearishPinBar(s, tf, sh);
}
bool HtfBullishClosedBar(const string s, const ENUM_TIMEFRAMES htf)
{
return (iClose(s, htf, 1) > iOpen(s, htf, 1));
}
bool HtfBearishClosedBar(const string s, const ENUM_TIMEFRAMES htf)
{
return (iClose(s, htf, 1) < iOpen(s, htf, 1));
}
bool ConfirmLong(const string s)
{
if(!InpRequireHtfCandleDir && !InpRequireHtfPattern)
return true;
if(InpRequireHtfCandleDir && !HtfBullishClosedBar(s, InpConfirmTF))
return false;
if(InpRequireHtfPattern && !BullishPatternBar(s, InpConfirmTF, 1))
return false;
return true;
}
bool ConfirmShort(const string s)
{
if(!InpRequireHtfCandleDir && !InpRequireHtfPattern)
return true;
if(InpRequireHtfCandleDir && !HtfBearishClosedBar(s, InpConfirmTF))
return false;
if(InpRequireHtfPattern && !BearishPatternBar(s, InpConfirmTF, 1))
return false;
return true;
}
bool ValidatedLongSetup(const string s)
{
if(!BullishPatternBar(s, InpSignalTF, 1))
return false;
return ConfirmLong(s);
}
bool ValidatedShortSetup(const string s)
{
if(!BearishPatternBar(s, InpSignalTF, 1))
return false;
return ConfirmShort(s);
}
bool HasOurPosition(const string s, const int magic, int &dir)
{
dir = -1;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
const ulong ticket = PositionGetTicket(i);
if(ticket == 0 || !PositionSelectByTicket(ticket))
continue;
if(PositionGetString(POSITION_SYMBOL) != s)
continue;
if((int)PositionGetInteger(POSITION_MAGIC) != magic)
continue;
const long typ = PositionGetInteger(POSITION_TYPE);
dir = (typ == POSITION_TYPE_BUY) ? 0 : 1;
return true;
}
return false;
}
bool CloseOurPositions(const string s, const int magic)
{
bool ok = true;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
const ulong ticket = PositionGetTicket(i);
if(ticket == 0 || !PositionSelectByTicket(ticket))
continue;
if(PositionGetString(POSITION_SYMBOL) != s)
continue;
if((int)PositionGetInteger(POSITION_MAGIC) != magic)
continue;
if(!g_trade.PositionClose(ticket))
ok = false;
}
return ok;
}
int OnInit()
{
g_sym = (StringLen(InpSymbol) == 0) ? _Symbol : InpSymbol;
if(!SymbolSelect(g_sym, true))
{
Print("SymbolSelect failed: ", g_sym);
return INIT_FAILED;
}
g_trade.SetExpertMagicNumber(InpMagic);
g_trade.SetDeviationInPoints(InpSlippagePoints);
g_trade.SetTypeFilling(ResolveFilling(g_sym));
return INIT_SUCCEEDED;
}
void OnDeinit(const int reason)
{
}
void OnTick()
{
if(!IsNewSignalBar())
return;
if(Bars(g_sym, InpSignalTF) < 5 || Bars(g_sym, InpConfirmTF) < 5)
return;
if(!SpreadOk(g_sym))
return;
const bool longSetup = ValidatedLongSetup(g_sym);
const bool shortSetup = ValidatedShortSetup(g_sym);
int dir = -1;
bool has = HasOurPosition(g_sym, InpMagic, dir);
if(has)
{
if(dir == 0)
{
bool adverse = false;
if(InpCloseOnAdversePattern)
{
if(BearishPatternBar(g_sym, InpSignalTF, 1) || BearishPatternBar(g_sym, InpConfirmTF, 1))
adverse = true;
}
const bool reverse = (InpCloseOnReverseSignal && shortSetup);
if(adverse || reverse)
CloseOurPositions(g_sym, InpMagic);
}
else if(dir == 1)
{
bool adverse = false;
if(InpCloseOnAdversePattern)
{
if(BullishPatternBar(g_sym, InpSignalTF, 1) || BullishPatternBar(g_sym, InpConfirmTF, 1))
adverse = true;
}
const bool reverse = (InpCloseOnReverseSignal && longSetup);
if(adverse || reverse)
CloseOurPositions(g_sym, InpMagic);
}
}
has = HasOurPosition(g_sym, InpMagic, dir);
if(InpOnlyOnePosition && has)
return;
if(longSetup && !shortSetup)
{
const double ask = SymbolInfoDouble(g_sym, SYMBOL_ASK);
g_trade.Buy(InpLots, g_sym, ask, 0.0, 0.0, "CandlePattern long");
}
else if(shortSetup && !longSetup)
{
const double bid = SymbolInfoDouble(g_sym, SYMBOL_BID);
g_trade.Sell(InpLots, g_sym, bid, 0.0, 0.0, "CandlePattern short");
}
}
File diff suppressed because it is too large Load Diff
+425
View File
@@ -0,0 +1,425 @@
//+------------------------------------------------------------------+
//| DerivativePlots.mq5 |
//| Subwindow line plots for d1 / d2 / d3 — use with Derivative EA |
//| Compile into MQL5\\Indicators\\ (same name). EA can ChartIndicatorAdd.|
//+------------------------------------------------------------------+
#property copyright "Lab"
#property link ""
#property version "1.10"
#property indicator_separate_window
#property indicator_buffers 3
#property indicator_plots 3
#property description "Plots d1 d2 d3 below chart. Match inputs to Derivative EA."
#property indicator_label1 "d1 velocity"
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrDodgerBlue
#property indicator_width1 1
#property indicator_label2 "d2 acceleration"
#property indicator_type2 DRAW_LINE
#property indicator_color2 clrOrange
#property indicator_width2 1
#property indicator_label3 "d3 jerk"
#property indicator_type3 DRAW_LINE
#property indicator_color3 clrMagenta
#property indicator_width3 1
enum ENUM_DERIVATIVE_VIEW
{
DERIVATIVE_ALL = 0,
DERIVATIVE_LEVEL_1 = 1,
DERIVATIVE_LEVEL_2 = 2,
DERIVATIVE_LEVEL_3 = 3
};
input group "=== Source ==="
input ENUM_APPLIED_PRICE InpAppliedPrice = PRICE_CLOSE;
input group "=== Layout ==="
input ENUM_DERIVATIVE_VIEW InpWhichDerivative = DERIVATIVE_ALL; // Single-line modes clear other buffers to EMPTY_VALUE so Y-scale matches the visible line
input bool InpUnifyPlotYScale = true; // Scale d2,d3 for comparable magnitude when normalized (shared subwindow)
input group "=== Calculus ==="
input int InpDiffStep = 1;
input bool InpNormalizePoints = true;
input group "=== Smoothing ==="
input int InpSmoothPeriod = 0;
input group "=== Status ==="
input bool InpShowValueBanner = true; // Text label; short name is DERIV_ALL / DERIV_d1 / DERIV_d2 / DERIV_d3 for ChartWindowFind
input group "=== Debug (Experts / Journal) ==="
input bool InpDebugTrace = false; // Print diagnostics to Experts tab
input bool InpDebugLogEveryCalculate = false; // Log every OnCalculate (very verbose)
double ExtD1[];
double ExtD2[];
double ExtD3[];
string g_deriv_chart_title = "DERIV_ALL";
string g_deriv_stat_obj = "DerivPV_ALL";
void SetupDerivIdentity()
{
switch(InpWhichDerivative)
{
case DERIVATIVE_ALL:
g_deriv_chart_title = "DERIV_ALL";
g_deriv_stat_obj = "DerivPV_ALL";
break;
case DERIVATIVE_LEVEL_1:
g_deriv_chart_title = "DERIV_d1";
g_deriv_stat_obj = "DerivPV_d1";
break;
case DERIVATIVE_LEVEL_2:
g_deriv_chart_title = "DERIV_d2";
g_deriv_stat_obj = "DerivPV_d2";
break;
default:
g_deriv_chart_title = "DERIV_d3";
g_deriv_stat_obj = "DerivPV_d3";
break;
}
}
// OnCalculate passes OHLC with index 0 = oldest bar (non-series). Do not ArraySetAsSeries() those arrays.
double AppliedPriceRowNs(const int pos, const double &open[], const double &high[],
const double &low[], const double &close[])
{
switch(InpAppliedPrice)
{
case PRICE_OPEN: return open[pos];
case PRICE_HIGH: return high[pos];
case PRICE_LOW: return low[pos];
case PRICE_CLOSE: return close[pos];
case PRICE_MEDIAN: return (high[pos] + low[pos]) * 0.5;
case PRICE_TYPICAL: return (high[pos] + low[pos] + close[pos]) / 3.0;
case PRICE_WEIGHTED: return (high[pos] + low[pos] + close[pos] + close[pos]) / 4.0;
default: return close[pos];
}
}
void SmoothPriceArrayNs(const int total, const double &src[], double &dst[])
{
ArrayResize(dst, total);
const int p = InpSmoothPeriod;
if(p <= 1)
{
ArrayCopy(dst, src);
return;
}
const double alpha = 2.0 / (p + 1.0);
dst[0] = src[0];
for(int pos = 1; pos < total; pos++)
dst[pos] = alpha * src[pos] + (1.0 - alpha) * dst[pos - 1];
}
double SrcNs(const int pos, const bool useSmooth, const double &smooth[], const double &raw[])
{
return useSmooth ? smooth[pos] : raw[pos];
}
double DerivativeScalePts()
{
double pt = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
if(pt <= 0.0 || !MathIsValidNumber(pt))
pt = _Point;
if(!InpNormalizePoints)
return 1.0;
if(pt <= 0.0)
return 1.0;
return pt;
}
void DerivPlotsTrace(const int rates_total, const int prev_calculated,
const int h, const int min_bars, const double scale, const bool useSmooth,
const double &close[], const double &WorkNs[], const datetime &time[])
{
if(!InpDebugTrace)
return;
static int s_call = 0;
s_call++;
const int newest = rates_total - 1;
const datetime barOpen = time[newest];
static datetime s_prevBarOpen = 0;
const bool isNewBarTime = (barOpen != s_prevBarOpen);
if(isNewBarTime)
s_prevBarOpen = barOpen;
const bool fullRecalc = (prev_calculated == 0);
if(InpDebugLogEveryCalculate)
{
PrintFormat("DERIV_PLOTS #%d prev_calc=%d rates=%d bar=%s | d1[0]=%.8g d2[0]=%.8g d3[0]=%.8g",
s_call, prev_calculated, rates_total, TimeToString(barOpen, TIME_DATE | TIME_MINUTES),
ExtD1[0], ExtD2[0], ExtD3[0]);
return;
}
if(fullRecalc)
{
const double pt = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
const double rawStep = (newest >= h) ? (WorkNs[newest] - WorkNs[newest - h]) : 0.0;
PrintFormat("DERIV_PLOTS FULL_CALC #%d sym=%s rates=%d prev_calc=%d h=%d min_need=%d smooth=%s which=%d",
s_call, _Symbol, rates_total, prev_calculated, h, min_bars,
useSmooth ? "on" : "off", (int)InpWhichDerivative);
PrintFormat(" scale=%.12g normalize=%s SYPOINT=%.12g _Point=%.12g SYM_DIGITS=%d",
scale, InpNormalizePoints ? "on" : "off", pt, _Point,
(int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS));
PrintFormat(" close[oldest]=%.8f close[newest]=%.8f rawStep(newest..newest-h)=%.8f",
close[0], close[newest], rawStep);
PrintFormat(" series buf [0]=current bar: d1=%.8g d2=%.8g d3=%.8g (EMPTY_VALUE=%.8g)",
ExtD1[0], ExtD2[0], ExtD3[0], EMPTY_VALUE);
}
else if(isNewBarTime)
{
PrintFormat("DERIV_PLOTS BAR %s rates=%d prev_calc=%d | d1[0]=%.8g d2[0]=%.8g d3[0]=%.8g",
TimeToString(barOpen, TIME_DATE | TIME_MINUTES), rates_total, prev_calculated,
ExtD1[0], ExtD2[0], ExtD3[0]);
}
}
string FormatPlotVal(const double v)
{
if(v == EMPTY_VALUE || !MathIsValidNumber(v))
return "—";
return DoubleToString(v, 4);
}
void UpdateValueBanner(const int rates_total)
{
if(!InpShowValueBanner || rates_total < 1)
return;
string txt = "";
switch(InpWhichDerivative)
{
case DERIVATIVE_ALL:
txt = StringFormat("d1=%s d2=%s d3=%s (h=%d sm=%d%s)",
FormatPlotVal(ExtD1[0]), FormatPlotVal(ExtD2[0]), FormatPlotVal(ExtD3[0]),
InpDiffStep, InpSmoothPeriod, InpUnifyPlotYScale ? " unifyY" : "");
break;
case DERIVATIVE_LEVEL_1:
txt = StringFormat("d1=%s", FormatPlotVal(ExtD1[0]));
break;
case DERIVATIVE_LEVEL_2:
txt = StringFormat("d2=%s", FormatPlotVal(ExtD2[0]));
break;
default:
txt = StringFormat("d3=%s", FormatPlotVal(ExtD3[0]));
break;
}
IndicatorSetString(INDICATOR_SHORTNAME, g_deriv_chart_title);
const int sub = ChartWindowFind(0, g_deriv_chart_title);
if(sub < 0)
return;
if(ObjectFind(0, g_deriv_stat_obj) < 0)
{
if(!ObjectCreate(0, g_deriv_stat_obj, OBJ_LABEL, sub, 0, 0))
return;
ObjectSetInteger(0, g_deriv_stat_obj, OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(0, g_deriv_stat_obj, OBJPROP_ANCHOR, ANCHOR_LEFT_UPPER);
ObjectSetInteger(0, g_deriv_stat_obj, OBJPROP_XDISTANCE, 6);
ObjectSetInteger(0, g_deriv_stat_obj, OBJPROP_YDISTANCE, 16);
ObjectSetInteger(0, g_deriv_stat_obj, OBJPROP_COLOR, clrSilver);
ObjectSetInteger(0, g_deriv_stat_obj, OBJPROP_FONTSIZE, 9);
ObjectSetString(0, g_deriv_stat_obj, OBJPROP_FONT, "Consolas");
ObjectSetInteger(0, g_deriv_stat_obj, OBJPROP_SELECTABLE, false);
ObjectSetInteger(0, g_deriv_stat_obj, OBJPROP_HIDDEN, true);
}
ObjectSetString(0, g_deriv_stat_obj, OBJPROP_TEXT, txt);
}
// Hide unused buffers from autoscale: DRAW_NONE plots can still skew separate-window limits if buffers hold numbers.
void MaskBuffersForDerivativeView()
{
switch(InpWhichDerivative)
{
case DERIVATIVE_ALL:
break;
case DERIVATIVE_LEVEL_1:
ArrayInitialize(ExtD2, EMPTY_VALUE);
ArrayInitialize(ExtD3, EMPTY_VALUE);
break;
case DERIVATIVE_LEVEL_2:
ArrayInitialize(ExtD1, EMPTY_VALUE);
ArrayInitialize(ExtD3, EMPTY_VALUE);
break;
default:
ArrayInitialize(ExtD1, EMPTY_VALUE);
ArrayInitialize(ExtD2, EMPTY_VALUE);
break;
}
}
void ApplyDerivativeViewMode()
{
switch(InpWhichDerivative)
{
case DERIVATIVE_ALL:
PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_LINE);
PlotIndexSetInteger(1, PLOT_DRAW_TYPE, DRAW_LINE);
PlotIndexSetInteger(2, PLOT_DRAW_TYPE, DRAW_LINE);
PlotIndexSetInteger(0, PLOT_LINE_COLOR, clrDodgerBlue);
PlotIndexSetInteger(1, PLOT_LINE_COLOR, clrOrange);
PlotIndexSetInteger(2, PLOT_LINE_COLOR, clrMagenta);
PlotIndexSetInteger(0, PLOT_LINE_WIDTH, 2);
PlotIndexSetInteger(1, PLOT_LINE_WIDTH, 3);
PlotIndexSetInteger(2, PLOT_LINE_WIDTH, 3);
PlotIndexSetInteger(0, PLOT_LINE_STYLE, STYLE_SOLID);
PlotIndexSetInteger(1, PLOT_LINE_STYLE, STYLE_SOLID);
PlotIndexSetInteger(2, PLOT_LINE_STYLE, STYLE_SOLID);
PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
PlotIndexSetDouble(2, PLOT_EMPTY_VALUE, EMPTY_VALUE);
break;
case DERIVATIVE_LEVEL_1:
PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_LINE);
PlotIndexSetInteger(1, PLOT_DRAW_TYPE, DRAW_NONE);
PlotIndexSetInteger(2, PLOT_DRAW_TYPE, DRAW_NONE);
PlotIndexSetInteger(0, PLOT_LINE_COLOR, clrDodgerBlue);
PlotIndexSetInteger(0, PLOT_LINE_WIDTH, 2);
PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
break;
case DERIVATIVE_LEVEL_2:
PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_NONE);
PlotIndexSetInteger(1, PLOT_DRAW_TYPE, DRAW_LINE);
PlotIndexSetInteger(2, PLOT_DRAW_TYPE, DRAW_NONE);
PlotIndexSetInteger(1, PLOT_LINE_COLOR, clrOrange);
PlotIndexSetInteger(1, PLOT_LINE_WIDTH, 3);
PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
break;
default:
PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_NONE);
PlotIndexSetInteger(1, PLOT_DRAW_TYPE, DRAW_NONE);
PlotIndexSetInteger(2, PLOT_DRAW_TYPE, DRAW_LINE);
PlotIndexSetInteger(2, PLOT_LINE_COLOR, clrMagenta);
PlotIndexSetInteger(2, PLOT_LINE_WIDTH, 3);
PlotIndexSetDouble(2, PLOT_EMPTY_VALUE, EMPTY_VALUE);
break;
}
}
int OnInit()
{
SetIndexBuffer(0, ExtD1, INDICATOR_DATA);
SetIndexBuffer(1, ExtD2, INDICATOR_DATA);
SetIndexBuffer(2, ExtD3, INDICATOR_DATA);
SetupDerivIdentity();
ApplyDerivativeViewMode();
IndicatorSetString(INDICATOR_SHORTNAME, g_deriv_chart_title);
const int dig = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
IndicatorSetInteger(INDICATOR_DIGITS, MathMax(6, dig));
if(InpDebugTrace)
PrintFormat("DERIV_PLOTS INIT sym=%s applied=%s h=%d sm=%d norm=%s dbg_every_calc=%s",
_Symbol, EnumToString(InpAppliedPrice), InpDiffStep, InpSmoothPeriod,
InpNormalizePoints ? "on" : "off", InpDebugLogEveryCalculate ? "on" : "off");
return INIT_SUCCEEDED;
}
void OnDeinit(const int reason)
{
ObjectDelete(0, g_deriv_stat_obj);
}
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
const int h = MathMax(InpDiffStep, 1);
const int min_bars = 3 * h + 2;
ApplyDerivativeViewMode();
ArrayResize(ExtD1, rates_total);
ArrayResize(ExtD2, rates_total);
ArrayResize(ExtD3, rates_total);
ArraySetAsSeries(ExtD1, true);
ArraySetAsSeries(ExtD2, true);
ArraySetAsSeries(ExtD3, true);
ArrayInitialize(ExtD1, EMPTY_VALUE);
ArrayInitialize(ExtD2, EMPTY_VALUE);
ArrayInitialize(ExtD3, EMPTY_VALUE);
if(rates_total < min_bars)
{
if(InpDebugTrace)
PrintFormat("DERIV_PLOTS SHORT_HISTORY sym=%s rates=%d need=%d (3*h+2, h=%d) — buffers left EMPTY",
_Symbol, rates_total, min_bars, h);
return rates_total;
}
double WorkNs[];
ArrayResize(WorkNs, rates_total);
for(int pos = 0; pos < rates_total; pos++)
WorkNs[pos] = AppliedPriceRowNs(pos, open, high, low, close);
static double SmoothNs[];
SmoothPriceArrayNs(rates_total, WorkNs, SmoothNs);
const bool useSmooth = (InpSmoothPeriod > 1);
const double scale = DerivativeScalePts();
// Bar index pos: 0 = oldest, rates_total-1 = newest. Map to series buffer si = rates_total - 1 - pos (0 = current bar).
const double hs = (double)h * scale;
const bool unify = InpUnifyPlotYScale;
for(int pos = h; pos < rates_total; pos++)
{
const double d1 = (SrcNs(pos, useSmooth, SmoothNs, WorkNs) - SrcNs(pos - h, useSmooth, SmoothNs, WorkNs)) / ((double)h * scale);
const int si = rates_total - 1 - pos;
ExtD1[si] = d1;
}
for(int pos = 2 * h; pos < rates_total; pos++)
{
const double d1_pos = (SrcNs(pos, useSmooth, SmoothNs, WorkNs) - SrcNs(pos - h, useSmooth, SmoothNs, WorkNs)) / ((double)h * scale);
const double d1_pm = (SrcNs(pos - h, useSmooth, SmoothNs, WorkNs) - SrcNs(pos - 2 * h, useSmooth, SmoothNs, WorkNs)) / ((double)h * scale);
double d2 = (d1_pos - d1_pm) / ((double)h * scale);
if(unify)
d2 *= hs;
const int si = rates_total - 1 - pos;
ExtD2[si] = d2;
}
for(int pos = 3 * h; pos < rates_total; pos++)
{
const double d1_pos = (SrcNs(pos, useSmooth, SmoothNs, WorkNs) - SrcNs(pos - h, useSmooth, SmoothNs, WorkNs)) / ((double)h * scale);
const double d1_pm = (SrcNs(pos - h, useSmooth, SmoothNs, WorkNs) - SrcNs(pos - 2 * h, useSmooth, SmoothNs, WorkNs)) / ((double)h * scale);
const double d1_pm2 = (SrcNs(pos - 2 * h, useSmooth, SmoothNs, WorkNs) - SrcNs(pos - 3 * h, useSmooth, SmoothNs, WorkNs)) / ((double)h * scale);
const double d2_pos = (d1_pos - d1_pm) / ((double)h * scale);
const double d2_pm = (d1_pm - d1_pm2) / ((double)h * scale);
double d3 = (d2_pos - d2_pm) / ((double)h * scale);
if(unify)
d3 *= hs * hs;
const int si = rates_total - 1 - pos;
ExtD3[si] = d3;
}
MaskBuffersForDerivativeView();
DerivPlotsTrace(rates_total, prev_calculated, h, min_bars, scale, useSmooth, close, WorkNs, time);
UpdateValueBanner(rates_total);
return rates_total;
}
//+------------------------------------------------------------------+
+383
View File
@@ -0,0 +1,383 @@
//+------------------------------------------------------------------+
//| TFXNZDUSD.mq5 |
//| NZDUSD: HTF directional bias + intraday bearish→bullish shift |
//| Mirrors a reactive workflow: higher TFs for bias (D1/W1), |
//| lower TFs (H4M15) for confirmation — long bias / pullback / |
//| reclaim entry. Not predictive; signals on closed bars. |
//+------------------------------------------------------------------+
#property copyright "Lab"
#property link ""
#property version "1.01"
#property description "NZDUSD long-bias EA: D1/W1 trend filter, intraday EMA cross after pullback streak, ATR risk."
#include <Trade/Trade.mqh>
input group "=== Symbol ==="
input string InpSymbol = "NZDUSD"; // Spot FX symbol (broker-specific)
input group "=== Timeframes (thesis) ==="
input ENUM_TIMEFRAMES InpBiasTF = PERIOD_D1; // Directional bias (monthly/weekly/daily idea → D1 default)
input ENUM_TIMEFRAMES InpHigherBiasTF = PERIOD_W1; // Optional second bias filter
input ENUM_TIMEFRAMES InpSignalTF = PERIOD_H4; // Intraday environment shift (H4 or lower)
input group "=== HTF bias (long-only, reactive) ==="
input bool InpUseWeeklyBias = true; // Require W1 close > W1 EMA
input int InpBiasEmaPeriod = 50; // EMA period on bias TFs
input bool InpAllowCounterBias = false; // If false, skip longs when D1 close < D1 EMA
input group "=== Intraday shift (bearish → bullish) ==="
input int InpFastEma = 8;
input int InpSlowEma = 21;
input int InpMinBearishBars = 3; // Min consecutive bars with fast EMA < slow before cross-up
input bool InpRequireBullBody = true; // Bullish closed candle on cross bar
input group "=== Risk ==="
input double InpLots = 0.10;
input int InpMagic = 926001;
input int InpSlippagePoints = 20;
input int InpMaxSpreadPoints = 40;
input bool InpUseAtrStops = true;
input int InpAtrPeriod = 14;
input double InpSlAtrMult = 1.5;
input double InpTpAtrMult = 2.5;
input double InpMinStopPoints = 50;
input int InpMaxPositions = 1;
input group "=== Session (optional) ==="
input bool InpUseSessionFilter = false;
input int InpSessionStartHour = 7; // Server hour start
input int InpSessionEndHour = 20; // Server hour end (exclusive if cross midnight handled below)
CTrade g_trade;
int g_atrSig = INVALID_HANDLE;
int g_emaBiasD1 = INVALID_HANDLE;
int g_emaBiasW1 = INVALID_HANDLE;
int g_emaFastSig = INVALID_HANDLE;
int g_emaSlowSig = INVALID_HANDLE;
/// Effective TFs after sanity check (genetic optimizers often pass invalid ENUM integers).
ENUM_TIMEFRAMES g_effBiasTF = PERIOD_D1;
ENUM_TIMEFRAMES g_effHigherBiasTF = PERIOD_W1;
ENUM_TIMEFRAMES g_effSignalTF = PERIOD_H4;
datetime g_lastSignalBar = 0;
// Maps garbage timeframe integers from optimization to nearest supported standard period.
ENUM_TIMEFRAMES NearestStandardTf(const ENUM_TIMEFRAMES raw)
{
if(PeriodSeconds(raw) > 0)
return raw;
const ENUM_TIMEFRAMES cand[] =
{
PERIOD_M15, PERIOD_M30, PERIOD_H1, PERIOD_H4, PERIOD_D1, PERIOD_W1
};
const long r = (long)raw;
ENUM_TIMEFRAMES best = PERIOD_H4;
long bestDist = -1;
for(int i = 0; i < ArraySize(cand); i++)
{
if(PeriodSeconds(cand[i]) <= 0)
continue;
const long diff = r - (long)cand[i];
const long d = (diff >= 0 ? diff : -diff);
if(bestDist < 0 || d < bestDist)
{
bestDist = d;
best = cand[i];
}
}
return best;
}
string WorkSymbol()
{
string s = InpSymbol;
StringTrimLeft(s);
StringTrimRight(s);
// .set files sometimes concatenate optimization payload into string inputs (e.g. "NZDUSD||0||...")
const int bar = StringFind(s, "|");
if(bar >= 0)
s = StringSubstr(s, 0, bar);
StringTrimRight(s);
return (StringLen(s) > 0 ? s : _Symbol);
}
bool SessionOk()
{
if(!InpUseSessionFilter)
return true;
MqlDateTime dt;
TimeToStruct(TimeCurrent(), dt);
int h = dt.hour;
if(InpSessionStartHour <= InpSessionEndHour)
return (h >= InpSessionStartHour && h < InpSessionEndHour);
return (h >= InpSessionStartHour || h < InpSessionEndHour);
}
double Buf1(const int handle, const int shift)
{
double b[];
ArraySetAsSeries(b, true);
if(CopyBuffer(handle, 0, shift, 1, b) != 1)
return 0.0;
return b[0];
}
bool CopyClose(const string sym, const ENUM_TIMEFRAMES tf, const int shift, double &out)
{
double c[];
ArraySetAsSeries(c, true);
if(CopyClose(sym, tf, shift, 1, c) != 1)
return false;
out = c[0];
return true;
}
bool HtfLongBias(const string sym)
{
double cD1 = 0.0, eD1 = 0.0;
if(!CopyClose(sym, g_effBiasTF, 1, cD1))
return false;
eD1 = Buf1(g_emaBiasD1, 1);
if(eD1 <= 0.0)
return false;
if(!InpAllowCounterBias && cD1 <= eD1)
return false;
if(InpUseWeeklyBias)
{
double cW1 = 0.0, eW1 = 0.0;
if(!CopyClose(sym, g_effHigherBiasTF, 1, cW1))
return false;
eW1 = Buf1(g_emaBiasW1, 1);
if(eW1 <= 0.0)
return false;
if(cW1 <= eW1)
return false;
}
return true;
}
int CountConsecutiveBearishEma(const string sym, const int fromShift, const int maxLookback)
{
double f[], s[];
ArraySetAsSeries(f, true);
ArraySetAsSeries(s, true);
int need = maxLookback + fromShift;
if(CopyBuffer(g_emaFastSig, 0, 0, need, f) < need)
return 0;
if(CopyBuffer(g_emaSlowSig, 0, 0, need, s) < need)
return 0;
int n = 0;
for(int i = fromShift; i < fromShift + maxLookback; i++)
{
if(f[i] <= s[i])
n++;
else
break;
}
return n;
}
bool BullishCrossOnLastClosedBar(const string sym)
{
double f1 = Buf1(g_emaFastSig, 1);
double s1 = Buf1(g_emaSlowSig, 1);
double f2 = Buf1(g_emaFastSig, 2);
double s2 = Buf1(g_emaSlowSig, 2);
if(f1 <= 0.0 || s1 <= 0.0 || f2 <= 0.0 || s2 <= 0.0)
return false;
bool crossedUp = (f1 > s1 && f2 <= s2);
if(!crossedUp)
return false;
int bearStreak = CountConsecutiveBearishEma(sym, 2, 32);
if(bearStreak < InpMinBearishBars)
return false;
if(InpRequireBullBody)
{
MqlRates r[];
ArraySetAsSeries(r, true);
if(CopyRates(sym, g_effSignalTF, 1, 1, r) != 1)
return false;
if(r[0].close <= r[0].open)
return false;
}
return true;
}
double NormalizeVolumeLots(const string sym, double lots)
{
double minLot = SymbolInfoDouble(sym, SYMBOL_VOLUME_MIN);
double maxLot = SymbolInfoDouble(sym, SYMBOL_VOLUME_MAX);
double step = SymbolInfoDouble(sym, SYMBOL_VOLUME_STEP);
if(step > 0.0)
lots = MathFloor(lots / step) * step;
if(lots < minLot)
lots = minLot;
if(lots > maxLot)
lots = maxLot;
return lots;
}
int CountOurPositions(const string sym)
{
int total = 0;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket == 0 || !PositionSelectByTicket(ticket))
continue;
if(PositionGetString(POSITION_SYMBOL) != sym)
continue;
if((int)PositionGetInteger(POSITION_MAGIC) != InpMagic)
continue;
total++;
}
return total;
}
bool SpreadOk(const string sym)
{
long spreadPts = SymbolInfoInteger(sym, SYMBOL_SPREAD);
return ((double)spreadPts <= (double)InpMaxSpreadPoints);
}
void ComputeStopsBuy(const string sym, const double entry, double &sl, double &tp)
{
double ptsSl = InpMinStopPoints;
double ptsTp = InpMinStopPoints * 2.0;
if(InpUseAtrStops && g_atrSig != INVALID_HANDLE)
{
double atr = Buf1(g_atrSig, 1);
if(atr > 0.0)
{
double atrPts = atr / SymbolInfoDouble(sym, SYMBOL_POINT);
ptsSl = MathMax(atrPts * InpSlAtrMult, InpMinStopPoints);
ptsTp = MathMax(atrPts * InpTpAtrMult, InpMinStopPoints);
}
}
double p = SymbolInfoDouble(sym, SYMBOL_POINT);
sl = entry - ptsSl * p;
tp = entry + ptsTp * p;
long stopsLevel = SymbolInfoInteger(sym, SYMBOL_TRADE_STOPS_LEVEL);
double minDist = (double)stopsLevel * p;
if(minDist > 0.0)
{
if(entry - sl < minDist)
sl = entry - minDist;
if(tp - entry < minDist)
tp = entry + minDist;
}
int dg = (int)SymbolInfoInteger(sym, SYMBOL_DIGITS);
sl = NormalizeDouble(sl, dg);
tp = NormalizeDouble(tp, dg);
}
int OnInit()
{
string sym = WorkSymbol();
if(!SymbolSelect(sym, true))
{
Print("TFXNZDUSD: symbol not available: ", sym);
return INIT_FAILED;
}
g_effBiasTF = NearestStandardTf(InpBiasTF);
g_effHigherBiasTF = NearestStandardTf(InpHigherBiasTF);
g_effSignalTF = NearestStandardTf(InpSignalTF);
if(g_effBiasTF != InpBiasTF || g_effHigherBiasTF != InpHigherBiasTF || g_effSignalTF != InpSignalTF)
Print("TFXNZDUSD: resolved TFs — bias ", EnumToString(g_effBiasTF), " (in ", (long)InpBiasTF, ")",
" W1 ", EnumToString(g_effHigherBiasTF), " (in ", (long)InpHigherBiasTF, ")",
" signal ", EnumToString(g_effSignalTF), " (in ", (long)InpSignalTF, ")");
if(InpBiasEmaPeriod < 1 || InpFastEma < 1 || InpSlowEma < 1 || InpAtrPeriod < 1)
{
Print("TFXNZDUSD: EMA/ATR period must be >= 1");
return INIT_PARAMETERS_INCORRECT;
}
g_trade.SetExpertMagicNumber(InpMagic);
g_trade.SetDeviationInPoints(InpSlippagePoints);
g_trade.SetTypeFillingBySymbol(sym);
g_emaBiasD1 = iMA(sym, g_effBiasTF, InpBiasEmaPeriod, 0, MODE_EMA, PRICE_CLOSE);
g_emaBiasW1 = iMA(sym, g_effHigherBiasTF, InpBiasEmaPeriod, 0, MODE_EMA, PRICE_CLOSE);
g_emaFastSig = iMA(sym, g_effSignalTF, InpFastEma, 0, MODE_EMA, PRICE_CLOSE);
g_emaSlowSig = iMA(sym, g_effSignalTF, InpSlowEma, 0, MODE_EMA, PRICE_CLOSE);
g_atrSig = iATR(sym, g_effSignalTF, InpAtrPeriod);
if(g_emaBiasD1 == INVALID_HANDLE || g_emaFastSig == INVALID_HANDLE || g_emaSlowSig == INVALID_HANDLE ||
g_atrSig == INVALID_HANDLE)
{
Print("TFXNZDUSD: indicator init failed — check InpBiasTF/InpHigherBiasTF/InpSignalTF & symbol history");
return INIT_FAILED;
}
if(InpUseWeeklyBias && g_emaBiasW1 == INVALID_HANDLE)
{
Print("TFXNZDUSD: W1 bias handle failed");
return INIT_FAILED;
}
Print("TFXNZDUSD: ", sym, " eff TFs: bias=", EnumToString(g_effBiasTF), " higher=", EnumToString(g_effHigherBiasTF),
" signal=", EnumToString(g_effSignalTF));
return INIT_SUCCEEDED;
}
void OnDeinit(const int reason)
{
if(g_emaBiasD1 != INVALID_HANDLE) IndicatorRelease(g_emaBiasD1);
if(g_emaBiasW1 != INVALID_HANDLE) IndicatorRelease(g_emaBiasW1);
if(g_emaFastSig != INVALID_HANDLE) IndicatorRelease(g_emaFastSig);
if(g_emaSlowSig != INVALID_HANDLE) IndicatorRelease(g_emaSlowSig);
if(g_atrSig != INVALID_HANDLE) IndicatorRelease(g_atrSig);
}
void OnTick()
{
string sym = WorkSymbol();
datetime barOpen = iTime(sym, g_effSignalTF, 0);
if(barOpen == 0)
return;
if(barOpen == g_lastSignalBar)
return;
datetime prevBar = iTime(sym, g_effSignalTF, 1);
if(prevBar == 0)
return;
g_lastSignalBar = barOpen;
if(!SessionOk())
return;
if(!SpreadOk(sym))
return;
if(CountOurPositions(sym) >= InpMaxPositions)
return;
if(!HtfLongBias(sym))
return;
if(!BullishCrossOnLastClosedBar(sym))
return;
MqlTick tick;
if(!SymbolInfoTick(sym, tick))
return;
double lots = NormalizeVolumeLots(sym, InpLots);
double sl = 0.0, tp = 0.0;
ComputeStopsBuy(sym, tick.ask, sl, tp);
if(!g_trade.Buy(lots, sym, tick.ask, sl, tp, "TFX NZDUSD shift"))
Print("TFXNZDUSD Buy failed ret=", g_trade.ResultRetcode(), " ", g_trade.ResultRetcodeDescription());
}
//+------------------------------------------------------------------+
@@ -0,0 +1,42 @@
; saved for genetic optimization — TFXNZDUSD.mq5 (Strategy Tester → Inputs → Load)
; Repo format: Parameter=Value||Step||Min||Max||Optimize(Y/N)
; ENUM_TIMEFRAMES: H1=16385, H4=16388, D1=16408, W1=32769
; Do NOT optimize InpSignalTF as MinMax integers — MT5 genetic samples invalid values (e.g. 16386)
; between real enums and OnInit fails. Compare H1 vs H4 in separate runs, or rely on EA TF resolution.
; === Symbol ===
; String inputs: use bare name OR Value||Value||Value||Value||N — never use 0 as middle field (MT5 may feed the whole line into the string).
InpSymbol=NZDUSD
; === Timeframes (thesis) ===
InpBiasTF=16408||0||16408||16408||N
InpHigherBiasTF=32769||0||32769||32769||N
InpSignalTF=16388||0||16388||16388||N
; === HTF bias (long-only, reactive) ===
InpUseWeeklyBias=true||false||0||true||N
InpBiasEmaPeriod=50||2||34||120||Y
InpAllowCounterBias=false||false||0||true||N
; === Intraday shift (bearish → bullish) ===
InpFastEma=8||1||5||34||Y
InpSlowEma=21||2||15||55||Y
InpMinBearishBars=3||1||2||10||Y
InpRequireBullBody=true||false||0||true||N
; === Risk ===
InpLots=0.1||0.01||0.1||0.1||N
InpMagic=926001||0||926001||926001||N
InpSlippagePoints=20||0||20||20||N
InpMaxSpreadPoints=40||5||20||60||Y
InpUseAtrStops=true||false||0||true||N
InpAtrPeriod=14||1||7||28||Y
InpSlAtrMult=1.5||0.1||1.0||3.5||Y
InpTpAtrMult=2.5||0.2||1.5||5.0||Y
InpMinStopPoints=50.0||5.0||30.0||120.0||Y
InpMaxPositions=1||0||1||1||N
; === Session (optional) ===
InpUseSessionFilter=false||false||0||true||N
InpSessionStartHour=7||0||7||7||N
InpSessionEndHour=20||0||20||20||N
+367
View File
@@ -0,0 +1,367 @@
//+------------------------------------------------------------------+
//| TFXXAUUSDScalper.mq5 |
//| Gold (XAUUSD) Donchian breakout scalper — momentum / range |
//| breakout style suited to impulse-or-consolidate dynamics. |
//+------------------------------------------------------------------+
#property copyright "Lab"
#property link ""
#property version "1.00"
#property description "Donchian channel breakout on XAUUSD; optional consolidation filter; percent-risk or fixed lots."
#include <Trade/Trade.mqh>
input group "=== Instrument ==="
input string InpSymbol = "XAUUSD";
input group "=== Session ==="
input ENUM_TIMEFRAMES InpSignalTF = PERIOD_M5;
input bool InpUseSessionFilter = false;
input int InpSessionStartHour = 7;
input int InpSessionEndHour = 22;
input group "=== Donchian breakout ==="
input int InpDonchianPeriod = 20; // Lookback for channel high/low (past bars exclude signal bar)
input bool InpRequireFreshBreak = true; // Close[2] inside prior upper/lower band (no churn)
input bool InpTradeLong = true;
input bool InpTradeShort = true;
input group "=== Consolidation filter (horizontal → breakout) ==="
input bool InpUseNarrowChannelFilter = false;
input double InpMaxChannelWidthAtrMult = 3.0; // Upper-Lower <= this * ATR(shift 2)
input group "=== Stops & targets (Nick-style RR) ==="
input int InpSlBufferPoints = 30; // Beyond opposite Donchian / structural low-high
input double InpTpRiskReward = 2.0; // TP distance = RR * risk distance
input bool InpUseMidStopFallback = false; // Optional tighter SL at channel mid (more aggressive)
input group "=== Risk ==="
input bool InpUsePercentRisk = true;
input double InpRiskPercent = 1.0; // % balance per trade (video example)
input double InpFixedLots = 0.10;
input int InpMagic = 928001;
input int InpSlippagePoints = 50;
input int InpMaxSpreadPoints = 60;
input int InpMaxPositions = 1;
input group "=== Indicators ==="
input int InpAtrPeriod = 14;
CTrade g_trade;
int g_atr = INVALID_HANDLE;
datetime g_lastBar = 0;
string WorkSymbol()
{
string s = InpSymbol;
StringTrimLeft(s);
StringTrimRight(s);
const int bar = StringFind(s, "|");
if(bar >= 0)
s = StringSubstr(s, 0, bar);
StringTrimRight(s);
return (StringLen(s) > 0 ? s : _Symbol);
}
bool SessionOk()
{
if(!InpUseSessionFilter)
return true;
MqlDateTime dt;
TimeToStruct(TimeCurrent(), dt);
const int h = dt.hour;
if(InpSessionStartHour <= InpSessionEndHour)
return (h >= InpSessionStartHour && h < InpSessionEndHour);
return (h >= InpSessionStartHour || h < InpSessionEndHour);
}
double DonchianUpper(const string sym, const ENUM_TIMEFRAMES tf, const int period, const int shiftAnchor)
{
if(period < 1)
return 0.0;
double mx = -DBL_MAX;
for(int i = shiftAnchor + 1; i <= shiftAnchor + period; i++)
{
const double hi = iHigh(sym, tf, i);
if(hi > mx)
mx = hi;
}
return mx;
}
double DonchianLower(const string sym, const ENUM_TIMEFRAMES tf, const int period, const int shiftAnchor)
{
if(period < 1)
return 0.0;
double mn = DBL_MAX;
for(int i = shiftAnchor + 1; i <= shiftAnchor + period; i++)
{
const double lo = iLow(sym, tf, i);
if(lo < mn)
mn = lo;
}
return mn;
}
double AtrAt(const int shift)
{
double b[];
ArraySetAsSeries(b, true);
if(g_atr == INVALID_HANDLE || CopyBuffer(g_atr, 0, shift, 1, b) != 1)
return 0.0;
return b[0];
}
double NormalizeLots(const string sym, double lots)
{
double mn = SymbolInfoDouble(sym, SYMBOL_VOLUME_MIN);
double mx = SymbolInfoDouble(sym, SYMBOL_VOLUME_MAX);
double st = SymbolInfoDouble(sym, SYMBOL_VOLUME_STEP);
if(st > 0.0)
lots = MathFloor(lots / st) * st;
if(lots < mn)
lots = mn;
if(lots > mx)
lots = mx;
return lots;
}
bool MoneyPerLotAtSl(const string sym, const ENUM_ORDER_TYPE type, const double openPrice, const double slPrice, double &lossPerLot)
{
lossPerLot = 0.0;
double p = 0.0;
if(!OrderCalcProfit(type, sym, 1.0, openPrice, slPrice, p))
return false;
lossPerLot = MathAbs(p);
return (lossPerLot > 0.0);
}
double LotsFromPercentRisk(const string sym, const ENUM_ORDER_TYPE type, const double openPrice, const double slPrice)
{
double perLotLoss = 0.0;
if(!MoneyPerLotAtSl(sym, type, openPrice, slPrice, perLotLoss))
return InpFixedLots;
const double balance = AccountInfoDouble(ACCOUNT_BALANCE);
const double riskMoney = balance * (InpRiskPercent / 100.0);
if(riskMoney <= 0.0 || perLotLoss <= 0.0)
return NormalizeLots(sym, InpFixedLots);
double lots = riskMoney / perLotLoss;
return NormalizeLots(sym, lots);
}
bool SpreadOk(const string sym)
{
const long sp = SymbolInfoInteger(sym, SYMBOL_SPREAD);
return ((double)sp <= (double)InpMaxSpreadPoints);
}
int CountMagicPositions(const string sym)
{
int n = 0;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
const ulong t = PositionGetTicket(i);
if(t == 0 || !PositionSelectByTicket(t))
continue;
if(PositionGetString(POSITION_SYMBOL) != sym)
continue;
if((int)PositionGetInteger(POSITION_MAGIC) != InpMagic)
continue;
n++;
}
return n;
}
void BuildStopsBuy(const string sym, const double entry, const double upperD1, const double lowerD1,
double &sl, double &tp)
{
const double pt = SymbolInfoDouble(sym, SYMBOL_POINT);
const double buf = (double)InpSlBufferPoints * pt;
double riskDist = entry - (lowerD1 - buf);
sl = lowerD1 - buf;
if(InpUseMidStopFallback)
{
const double mid = (upperD1 + lowerD1) * 0.5;
const double distMid = entry - mid;
if(distMid > 0 && distMid < riskDist)
{
sl = mid - buf;
riskDist = entry - sl;
}
}
const long lvl = SymbolInfoInteger(sym, SYMBOL_TRADE_STOPS_LEVEL);
const double minD = (double)lvl * pt;
if(minD > 0.0 && entry - sl < minD)
sl = entry - minD;
riskDist = entry - sl;
tp = entry + riskDist * InpTpRiskReward;
if(minD > 0.0 && tp - entry < minD)
tp = entry + minD;
const int dg = (int)SymbolInfoInteger(sym, SYMBOL_DIGITS);
sl = NormalizeDouble(sl, dg);
tp = NormalizeDouble(tp, dg);
}
void BuildStopsSell(const string sym, const double entry, const double upperD1, const double lowerD1,
double &sl, double &tp)
{
const double pt = SymbolInfoDouble(sym, SYMBOL_POINT);
const double buf = (double)InpSlBufferPoints * pt;
double riskDist = (upperD1 + buf) - entry;
sl = upperD1 + buf;
if(InpUseMidStopFallback)
{
const double mid = (upperD1 + lowerD1) * 0.5;
const double distMid = mid - entry;
if(distMid > 0 && distMid < riskDist)
{
sl = mid + buf;
riskDist = sl - entry;
}
}
const long lvl = SymbolInfoInteger(sym, SYMBOL_TRADE_STOPS_LEVEL);
const double minD = (double)lvl * pt;
if(minD > 0.0 && sl - entry < minD)
sl = entry + minD;
riskDist = sl - entry;
tp = entry - riskDist * InpTpRiskReward;
if(minD > 0.0 && entry - tp < minD)
tp = entry - minD;
const int dg = (int)SymbolInfoInteger(sym, SYMBOL_DIGITS);
sl = NormalizeDouble(sl, dg);
tp = NormalizeDouble(tp, dg);
}
bool NarrowChannelOk(const string sym, const ENUM_TIMEFRAMES tf, const int period)
{
if(!InpUseNarrowChannelFilter)
return true;
const double up = DonchianUpper(sym, tf, period, 2);
const double lo = DonchianLower(sym, tf, period, 2);
const double atr = AtrAt(2);
if(up <= 0 || lo <= 0 || atr <= 0)
return false;
const double width = up - lo;
return (width <= atr * InpMaxChannelWidthAtrMult);
}
int OnInit()
{
const string sym = WorkSymbol();
if(!SymbolSelect(sym, true))
{
Print("TFXXAUUSDScalper: symbol not available: ", sym);
return INIT_FAILED;
}
if(InpDonchianPeriod < 2)
{
Print("TFXXAUUSDScalper: InpDonchianPeriod must be >= 2");
return INIT_PARAMETERS_INCORRECT;
}
g_trade.SetExpertMagicNumber(InpMagic);
g_trade.SetDeviationInPoints(InpSlippagePoints);
g_trade.SetTypeFillingBySymbol(sym);
g_atr = iATR(sym, InpSignalTF, InpAtrPeriod);
if(g_atr == INVALID_HANDLE)
{
Print("TFXXAUUSDScalper: ATR init failed");
return INIT_FAILED;
}
Print("TFXXAUUSDScalper: ", sym, " ", EnumToString(InpSignalTF),
" Donchian=", InpDonchianPeriod, " RR=", InpTpRiskReward,
" risk%=", (InpUsePercentRisk ? DoubleToString(InpRiskPercent, 2) : "off"));
return INIT_SUCCEEDED;
}
void OnDeinit(const int reason)
{
if(g_atr != INVALID_HANDLE)
IndicatorRelease(g_atr);
g_atr = INVALID_HANDLE;
}
void OnTick()
{
const string sym = WorkSymbol();
const datetime t0 = iTime(sym, InpSignalTF, 0);
if(t0 == 0 || t0 == g_lastBar)
return;
g_lastBar = t0;
if(!SessionOk() || !SpreadOk(sym))
return;
if(CountMagicPositions(sym) >= InpMaxPositions)
return;
const int p = InpDonchianPeriod;
const double c1 = iClose(sym, InpSignalTF, 1);
const double c2 = iClose(sym, InpSignalTF, 2);
if(c1 <= 0.0 || c2 <= 0.0)
return;
const double up1 = DonchianUpper(sym, InpSignalTF, p, 1);
const double lo1 = DonchianLower(sym, InpSignalTF, p, 1);
const double up2 = DonchianUpper(sym, InpSignalTF, p, 2);
const double lo2 = DonchianLower(sym, InpSignalTF, p, 2);
if(up1 <= 0 || lo1 <= 0 || up2 <= 0 || lo2 <= 0)
return;
if(!NarrowChannelOk(sym, InpSignalTF, p))
return;
bool longSig = InpTradeLong && (c1 > up1);
bool shortSig = InpTradeShort && (c1 < lo1);
if(InpRequireFreshBreak)
{
longSig = longSig && (c2 <= up2);
shortSig = shortSig && (c2 >= lo2);
}
if(!longSig && !shortSig)
return;
MqlTick tick;
if(!SymbolInfoTick(sym, tick))
return;
if(longSig && !shortSig)
{
double sl = 0.0, tp = 0.0;
BuildStopsBuy(sym, tick.ask, up1, lo1, sl, tp);
const double lots = InpUsePercentRisk ? LotsFromPercentRisk(sym, ORDER_TYPE_BUY, tick.ask, sl) : NormalizeLots(sym, InpFixedLots);
if(!g_trade.Buy(lots, sym, tick.ask, sl, tp, "TFX Gold Donchian↑"))
Print("Buy failed ", g_trade.ResultRetcode(), " ", g_trade.ResultRetcodeDescription());
return;
}
if(shortSig && !longSig)
{
double sl = 0.0, tp = 0.0;
BuildStopsSell(sym, tick.bid, up1, lo1, sl, tp);
const double lots = InpUsePercentRisk ? LotsFromPercentRisk(sym, ORDER_TYPE_SELL, tick.bid, sl) : NormalizeLots(sym, InpFixedLots);
if(!g_trade.Sell(lots, sym, tick.bid, sl, tp, "TFX Gold Donchian↓"))
Print("Sell failed ", g_trade.ResultRetcode(), " ", g_trade.ResultRetcodeDescription());
return;
}
// Bothtrue — rare; skip to avoid ambiguous execution
}
//+------------------------------------------------------------------+
@@ -0,0 +1,44 @@
; TFXXAUUSDScalper.mq5 — Strategy Tester → Inputs → Load (Genetic optimization)
; Format: Parameter=Value||Step||Min||Max||Optimize(Y/N)
;
; ENUM_TIMEFRAMES (MT5): M1=1 M5=5 M15=15 M30=30 H1=16385 H4=16388 D1=16408
; Keep InpSignalTF fixed (single integer). Do not use MinMax sweeps on enums — genetic
; often tries invalid values between named periods and OnInit fails.
;
; Baseline aligned with Desktop 123.set (2026.05.08); magic corrected to 928001 (EA default).
; === Instrument ===
InpSymbol=XAUUSD
; === Session ===
InpSignalTF=5||0||5||5||N
InpUseSessionFilter=false||false||0||true||N
InpSessionStartHour=7||0||7||7||N
InpSessionEndHour=22||0||22||22||N
; === Donchian breakout ===
InpDonchianPeriod=20||2||10||80||Y
InpRequireFreshBreak=true||false||0||true||N
InpTradeLong=true||false||0||true||N
InpTradeShort=true||false||0||true||N
; === Consolidation filter (horizontal → breakout) ===
InpUseNarrowChannelFilter=false||false||0||true||N
InpMaxChannelWidthAtrMult=3.0||0.5||1.5||6.0||Y
; === Stops & targets (Nick-style RR) ===
InpSlBufferPoints=30||5||10||120||Y
InpTpRiskReward=2.0||0.25||1.25||4.0||Y
InpUseMidStopFallback=false||false||0||true||N
; === Risk ===
InpUsePercentRisk=true||false||0||true||N
InpRiskPercent=1.0||0.15||0.25||2.5||Y
InpFixedLots=0.1||0.01||0.1||0.1||N
InpMagic=928001||0||928001||928001||N
InpSlippagePoints=50||0||50||50||N
InpMaxSpreadPoints=60||5||20||100||Y
InpMaxPositions=1||0||1||1||N
; === Indicators ===
InpAtrPeriod=14||1||7||28||Y
@@ -0,0 +1,458 @@
//+------------------------------------------------------------------+
//| ScoringTrade.mq5 |
//| Generated by ChatGPT |
//| |
//+------------------------------------------------------------------+
#property strict
#include <Trade\Trade.mqh>
// Input parameters
input int MagicNumber = 42;
input int scoreThreshold = 5200; // Score threshold for trade entry
input int slopeThreshold = 93; // EMA slope threshold
input double maxScore = 7900; // Max score value for clamping
input int cooldownMinutes = 18; // Cooldown period in minutes (37 minutes)
input int tradeCooldownMinutes = 24; // Trade debounce cooldown period (5 minutes)
input ENUM_TIMEFRAMES emaTimeFrame = PERIOD_H1; // EMA Timeframe
input double delayClampAbsolute = 1690;
input int emaPeriod = 64; // EMA period
input double crossOverStep = 950;
input double slopeThresholdStep = 635;
input double emaDistanceStep = 150;
input double emaDecayStep = 0;
input double decayMultiplier = 0.08; // Decay multiplier
input double distanceThreshold = 28.5; // Set your distance threshold (adjust as necessary)
input double atrMultiplier = 7.6; // Multiplier for dynamic SL and TP calculation
input double TrailingStop = 5;
input bool UseTrailingStop = true;
input int maxCrossoverTrades = 4; // Maximum number of trades per crossover
input double max_drawdown = 0.1; // Maximum drawdown percentage
input bool resetCrossoverTradeOnDistance = false;
input int resetCrossoverNumber = 0;
input double minimumLotSize = 0.01;
input int maxTimeInPosition = 9;
input int tradeLengthThreshold = 98;
input int reverseTP = 32;
input int reverseLotSizeMultiplier = 15;
input int secondaryPositionHoldTime = 32;
// Global variables
int emaHandle; // EMA handle
double prevScore = 0; // Previous score
double currentScore = 0; // Current score
double emaPrevValue = 0; // Previous EMA value
double emaCurrentValue = 0; // Current EMA value
double emaSlope = 0; // EMA slope value
CTrade trade; // Trading object
datetime lastCrossoverTime = 0; // Time of last crossover
datetime lastTradeTime = 0; // Time of last trade
int crossoverTradeCount = 0; // Count of trades after each crossover
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit() {
// Create EMA handle (e.g., 14-period EMA on the closing price)
emaHandle = iMA(Symbol(), emaTimeFrame, emaPeriod, 0, MODE_EMA, PRICE_CLOSE);
if (emaHandle == INVALID_HANDLE) {
Print("Failed to create EMA handle");
return INIT_FAILED;
}
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
if (emaHandle != INVALID_HANDLE) {
IndicatorRelease(emaHandle);
emaHandle = INVALID_HANDLE;
}
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick() {
// Buffer to hold the EMA values
double emaBuffer[];
// Get dynamic lot size based on current balance and max drawdown
double lotSize = CalculateLotSize();
if(lotSize < minimumLotSize) {
lotSize = minimumLotSize;
}
// Get the current Ask and Bid prices
double Ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK);
double Bid = SymbolInfoDouble(Symbol(), SYMBOL_BID);
// Copy the last 2 EMA values (current and previous)
int copied = CopyBuffer(emaHandle, 0, 0, 2, emaBuffer);
if (copied < 2) {
Print("Failed to copy EMA values. Error code: ", GetLastError());
return;
}
// Get the current and previous EMA values
emaPrevValue = emaBuffer[1]; // Previous EMA value (index 1)
emaCurrentValue = emaBuffer[0]; // Current EMA value (index 0)
// Calculate the EMA slope (change in EMA values)
emaSlope = - (emaCurrentValue - emaPrevValue) * 100;
// Check for price action crossover with EMA
double closePrev = iClose(Symbol(), Period(), 1); // Close of previous bar
double closeCurr = iClose(Symbol(), Period(), 0); // Close of current bar
// Check if enough time has passed for the cooldown (cooldownMinutes)
if (TimeCurrent() - lastCrossoverTime >= cooldownMinutes * 60) {
if (closePrev < emaPrevValue && closeCurr > emaCurrentValue) { // Bullish crossover
Print("Bullish crossover");
currentScore += crossOverStep;
crossoverTradeCount = 0; // Reset trade count after new crossover
lastCrossoverTime = TimeCurrent(); // Update the last crossover time
}
else if (closePrev > emaPrevValue && closeCurr < emaCurrentValue) { // Bearish crossover
Print("Bearish crossover");
currentScore -= crossOverStep;
crossoverTradeCount = 0; // Reset trade count after new crossover
lastCrossoverTime = TimeCurrent(); // Update the last crossover time
}
}
// Check EMA slope
if (emaSlope > slopeThreshold) { // Positive slope
currentScore += slopeThresholdStep;
}
else if (emaSlope < -slopeThreshold) { // Negative slope
currentScore -= slopeThresholdStep;
}
else {
if (MathAbs(currentScore) > delayClampAbsolute) {
currentScore *= decayMultiplier;
}
}
if(UseTrailingStop) {
ApplyTrailingStop();
}
// Calculate distance to EMA and adjust score
double priceToEmaDistance = closeCurr - emaCurrentValue; // Distance between the current price and the EMA
if (MathAbs(priceToEmaDistance) > distanceThreshold) {
if (priceToEmaDistance > 0) { // Bullish (price above EMA)
currentScore += emaDistanceStep;
Print("Bullish distance score added. Price: ", closeCurr, " EMA: ", emaCurrentValue);
}
else if (priceToEmaDistance < 0) { // Bearish (price below EMA)
currentScore -= emaDistanceStep;
Print("Bearish distance score added. Price: ", closeCurr, " EMA: ", emaCurrentValue);
}
}
else {
if (currentScore > 0) {
currentScore -= emaDecayStep;
}
else {
currentScore += emaDecayStep;
}
}
// Close all positions if score crosses zero
if ((prevScore > 0 && currentScore <= 0) || (prevScore < 0 && currentScore >= 0)) {
Close_Position_MN(MagicNumber);
}
// Update the previous score
prevScore = currentScore;
if (crossoverTradeCount > maxCrossoverTrades) {
return;
}
// Debounce check: Ensure enough time has passed since the last trade
if (TimeCurrent() - lastTradeTime >= tradeCooldownMinutes * 60) {
// Calculate ATR (Average True Range) for stop loss calculation
double atrArray[];
int atrPeriod = 14; // ATR period (can be adjusted)
int copied = CopyBuffer(iATR(Symbol(), Period(), atrPeriod), 0, 0, 1, atrArray);
if (copied < 1) {
Print("Failed to get ATR values. Error code: ", GetLastError());
return;
}
// Get the current price (using Bid price)
double currentPrice = Bid;
// Get ATR value
double atrValue = atrArray[0]; // Latest ATR value
// Get the minimum stop level and freeze level for the symbol
long stopLevel = SymbolInfoInteger(Symbol(), SYMBOL_TRADE_STOPS_LEVEL);
long freezeLevel = SymbolInfoInteger(Symbol(), SYMBOL_TRADE_FREEZE_LEVEL);
// Calculate the minimum stop loss in price units (converted from pips)
double minStopLoss = stopLevel * SymbolInfoDouble(Symbol(), SYMBOL_POINT);
double minFreezeLevel = freezeLevel * SymbolInfoDouble(Symbol(), SYMBOL_POINT);
// Dynamic Stop Loss and Take Profit calculation based on ATR
double dynamicSL = atrValue * atrMultiplier;
double dynamicTP = atrValue * atrMultiplier;
// Adjust SL and TP if they are smaller than the minimum stop level
dynamicSL = MathMax(dynamicSL, minStopLoss);
dynamicTP = MathMax(dynamicTP, dynamicSL); // Ensure TP is at least the same as SL
// Trade logic based on the score
if (currentScore > scoreThreshold) { // Buy signal
if ((!PositionSelect(Symbol()) || PositionGetInteger(POSITION_MAGIC) != MagicNumber)
&& crossoverTradeCount < maxCrossoverTrades) {
Print("maxCrossover");
Print(crossoverTradeCount);
// Open buy position with dynamic SL and TP
trade.SetExpertMagicNumber(MagicNumber);
if (trade.Buy(lotSize, Symbol(), currentPrice, Bid - dynamicSL, 0)) {
Print("Buy order executed with score: ", currentScore);
crossoverTradeCount++; // Increment trade count
lastTradeTime = TimeCurrent(); // Update the last trade time
}
}
}
else if (currentScore < -scoreThreshold) { // Sell signal
if ((!PositionSelect(Symbol()) || PositionGetInteger(POSITION_MAGIC) != MagicNumber)
&& crossoverTradeCount < maxCrossoverTrades) {
Print("maxCrossover");
Print(crossoverTradeCount);
// Open sell position with dynamic SL and TP
trade.SetExpertMagicNumber(MagicNumber);
if (trade.Sell(lotSize, Symbol(), currentPrice, Ask + dynamicSL, 0)) {
Print("Sell order executed with score: ", currentScore);
crossoverTradeCount++; // Increment trade count
lastTradeTime = TimeCurrent(); // Update the last trade time
}
}
}
} else {
Print("Trade skipped due to debounce: ", currentScore);
}
// Check existing positions for profit and place reverse trade if needed
CheckPositions();
}
//+------------------------------------------------------------------+
//| Check existing positions for profit and place reverse trade if needed |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Check existing positions for duration and place reverse trade if needed |
//+------------------------------------------------------------------+
void CheckPositions() {
// Check if there are any open positions
if (PositionsTotal() > 0) {
// Check if there are exactly 2 open positions
if (PositionsTotal() == 2) {
for (int i = 0; i < PositionsTotal(); i++) {
ulong ticket = PositionGetTicket(i);
if (PositionSelectByTicket(ticket)) {
datetime openTime = (datetime)PositionGetInteger(POSITION_TIME);
long tradeLength = (long)(TimeCurrent() - openTime);
// Check if the trade has been open for more than the secondaryPositionHoldTime
if (tradeLength > secondaryPositionHoldTime * 60) { // Convert threshold to seconds
// Close all positions
CloseAllPositions();
Print("All positions closed due to exceeding secondaryPositionHoldTime");
return; // Exit the function after closing all positions
}
}
}
} else if (PositionsTotal() < 2) {
for (int i = 0; i < PositionsTotal(); i++) {
ulong ticket = PositionGetTicket(i);
if (PositionSelectByTicket(ticket)) {
double profit = PositionGetDouble(POSITION_PROFIT);
datetime openTime = (datetime)PositionGetInteger(POSITION_TIME);
long tradeLength = (long)(TimeCurrent() - openTime);
// Check if the trade has been open for more than the tradeLengthThreshold
if (tradeLength > tradeLengthThreshold * 60) { // Convert threshold to seconds
double lotSize = PositionGetDouble(POSITION_VOLUME);
double newLotSize = lotSize * reverseLotSizeMultiplier; // 10 times the original lot size
crossoverTradeCount = maxCrossoverTrades + 1;
// Place a reverse trade
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) {
trade.SetExpertMagicNumber(MagicNumber);
if (trade.Sell(newLotSize, Symbol(), SymbolInfoDouble(Symbol(), SYMBOL_BID))) {
Print("Reversal sell order executed with increased lot size");
} else {
Print("Failed to execute reversal sell order");
}
} else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) {
trade.SetExpertMagicNumber(MagicNumber);
if (trade.Buy(newLotSize, Symbol(), SymbolInfoDouble(Symbol(), SYMBOL_ASK))) {
Print("Reversal buy order executed with increased lot size");
} else {
Print("Failed to execute reversal buy order");
}
}
}
// Close the trade if profit meets the take profit level
if (profit >= reverseTP) {
Close_Position_MN(MagicNumber);
CloseAllPositions();
}
// Check if there is only one position and its volume is lotSize * reverseLotSizeMultiplier
if (PositionsTotal() == 1 && PositionGetDouble(POSITION_VOLUME) == minimumLotSize * reverseLotSizeMultiplier) {
trade.PositionClose(ticket);
Print("Single position with volume equal to lotSize * reverseLotSizeMultiplier closed");
}
// Get the current Ask and Bid prices
double Ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK);
double Bid = SymbolInfoDouble(Symbol(), SYMBOL_BID);
// Check if the double down trade is exited by stop loss
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY && PositionGetDouble(POSITION_SL) > 0 && Bid <= PositionGetDouble(POSITION_SL)) {
// Close the original trade
CloseOriginalTrade();
} else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL && PositionGetDouble(POSITION_SL) > 0 && Ask >= PositionGetDouble(POSITION_SL)) {
// Close the original trade
CloseOriginalTrade();
}
}
}
}
}
}
// Function to close the original trade
void CloseOriginalTrade() {
for (int i = PositionsTotal() - 1; i >= 0; i--) {
ulong ticket = PositionGetTicket(i);
if (PositionSelectByTicket(ticket)) {
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) {
trade.PositionClose(ticket);
Print("Original buy position closed due to double down stop loss.");
} else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) {
trade.PositionClose(ticket);
Print("Original sell position closed due to double down stop loss.");
}
}
}
}
//+------------------------------------------------------------------+
//| Function to close all positions |
//+------------------------------------------------------------------+
void CloseAllPositions() {
// Loop through all positions and close them
for (int i = PositionsTotal() - 1; i >= 0; i--) {
ulong ticket = PositionGetTicket(i);
if (PositionSelectByTicket(ticket)) {
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) {
trade.PositionClose(ticket);
Print("Buy position closed at score crossover.");
}
else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) {
trade.PositionClose(ticket);
Print("Sell position closed at score crossover.");
}
}
}
}
void ApplyTrailingStop()
{
for(int i=PositionsTotal()-1; i>=0; i--)
{
string symbol = PositionGetSymbol(i);
ulong PositionTicket = PositionGetTicket(i);
long trade_type = PositionGetInteger(POSITION_TYPE);
if(PositionGetInteger(POSITION_MAGIC) != MagicNumber) {
continue;
}
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(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(trade_type == 1)
{
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));
}
}
}
}
}
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);
}
}
}
//+------------------------------------------------------------------+
//| Calculate the dynamic lot size based on max drawdown |
//+------------------------------------------------------------------+
double CalculateLotSize()
{
double balance = AccountInfoDouble(ACCOUNT_BALANCE); // Get account balance
double allowedDrawdown = balance * max_drawdown; // Calculate allowed drawdown in account currency
double baseDrawdownPerLot = 150; // Assumed drawdown per 0.01 lots as per backtest
// Calculate lot size based on maximum drawdown
double lotSize = (allowedDrawdown / baseDrawdownPerLot) * 0.01;
return NormalizeDouble(lotSize, 2); // Normalize lot size to 2 decimal places
}

Some files were not shown because too many files have changed in this diff Show More