diff --git a/frontline/cluster-fuck/RSIConsolidationXAUUSD/RSIConsolidation.mq5 b/back-pedal/archive/RSIConsolidationXAUUSD/RSIConsolidation.mq5 similarity index 100% rename from frontline/cluster-fuck/RSIConsolidationXAUUSD/RSIConsolidation.mq5 rename to back-pedal/archive/RSIConsolidationXAUUSD/RSIConsolidation.mq5 diff --git a/frontline/cluster-fuck/RSIConsolidationXAUUSD/RSIConsolidation_optimization.set b/back-pedal/archive/RSIConsolidationXAUUSD/RSIConsolidation_optimization.set similarity index 100% rename from frontline/cluster-fuck/RSIConsolidationXAUUSD/RSIConsolidation_optimization.set rename to back-pedal/archive/RSIConsolidationXAUUSD/RSIConsolidation_optimization.set diff --git a/frontline/units/RSIScalpingXAUUSD/main.mq5 b/back-pedal/archive/RSIScalpingXAUUSD/main.mq5 similarity index 100% rename from frontline/units/RSIScalpingXAUUSD/main.mq5 rename to back-pedal/archive/RSIScalpingXAUUSD/main.mq5 diff --git a/frontline/cluster-fuck/RSIScalpingXAUUSD-trailing/report.html b/back-pedal/archive/RSIScalpingXAUUSD/report.html similarity index 100% rename from frontline/cluster-fuck/RSIScalpingXAUUSD-trailing/report.html rename to back-pedal/archive/RSIScalpingXAUUSD/report.html diff --git a/frontline/cluster-fuck/RSIScalpingXAUUSD-trailing/report.png b/back-pedal/archive/RSIScalpingXAUUSD/report.png similarity index 100% rename from frontline/cluster-fuck/RSIScalpingXAUUSD-trailing/report.png rename to back-pedal/archive/RSIScalpingXAUUSD/report.png diff --git a/frontline/cluster-fuck/SuperEMAXAUUSD/SuperEMA.set b/back-pedal/archive/SuperEMAXAUUSD/SuperEMA.set similarity index 100% rename from frontline/cluster-fuck/SuperEMAXAUUSD/SuperEMA.set rename to back-pedal/archive/SuperEMAXAUUSD/SuperEMA.set diff --git a/frontline/cluster-fuck/SuperEMAXAUUSD/main.mq5 b/back-pedal/archive/SuperEMAXAUUSD/main.mq5 similarity index 100% rename from frontline/cluster-fuck/SuperEMAXAUUSD/main.mq5 rename to back-pedal/archive/SuperEMAXAUUSD/main.mq5 diff --git a/backtesting/MT5/test_setup.py b/backtesting/MT5/test_setup.py index d268434..d19edd1 100644 --- a/backtesting/MT5/test_setup.py +++ b/backtesting/MT5/test_setup.py @@ -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() diff --git a/frontline/cluster-fuck/DarvasBoxXAUUSD/DarvasBoxXAUUSD_Genetic_Optimization.set b/frontline/cluster-fuck/DarvasBoxXAUUSD/DarvasBoxXAUUSD_Genetic_Optimization.set deleted file mode 100644 index ca12828..0000000 --- a/frontline/cluster-fuck/DarvasBoxXAUUSD/DarvasBoxXAUUSD_Genetic_Optimization.set +++ /dev/null @@ -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 diff --git a/frontline/cluster-fuck/DarvasBoxXAUUSD/main.mq5 b/frontline/cluster-fuck/DarvasBoxXAUUSD/main.mq5 deleted file mode 100644 index 6da93f9..0000000 --- a/frontline/cluster-fuck/DarvasBoxXAUUSD/main.mq5 +++ /dev/null @@ -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 -#include -#include -#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); -} diff --git a/frontline/cluster-fuck/EMASlopeDistanceCocktailXAUUSD-trailing/main.mq5 b/frontline/cluster-fuck/EMASlopeDistanceCocktailXAUUSD-trailing/main.mq5 deleted file mode 100644 index 6d849c0..0000000 --- a/frontline/cluster-fuck/EMASlopeDistanceCocktailXAUUSD-trailing/main.mq5 +++ /dev/null @@ -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 -#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()); - } -} - -//+------------------------------------------------------------------+ diff --git a/frontline/cluster-fuck/EMASlopeDistanceCocktailXAUUSD-trailing/report.html b/frontline/cluster-fuck/EMASlopeDistanceCocktailXAUUSD-trailing/report.html deleted file mode 100644 index 8d9931f..0000000 Binary files a/frontline/cluster-fuck/EMASlopeDistanceCocktailXAUUSD-trailing/report.html and /dev/null differ diff --git a/frontline/cluster-fuck/EMASlopeDistanceCocktailXAUUSD-trailing/report.png b/frontline/cluster-fuck/EMASlopeDistanceCocktailXAUUSD-trailing/report.png deleted file mode 100644 index c0bf45b..0000000 Binary files a/frontline/cluster-fuck/EMASlopeDistanceCocktailXAUUSD-trailing/report.png and /dev/null differ diff --git a/frontline/cluster-fuck/RSICrossOverReversalXAUUSD/main.mq5 b/frontline/cluster-fuck/RSICrossOverReversalXAUUSD/main.mq5 deleted file mode 100644 index 8412fa6..0000000 --- a/frontline/cluster-fuck/RSICrossOverReversalXAUUSD/main.mq5 +++ /dev/null @@ -1,295 +0,0 @@ -// Input Parameters -#include -#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; -} \ No newline at end of file diff --git a/frontline/cluster-fuck/RSIMidPointHijackXAUUSD/main.mq5 b/frontline/cluster-fuck/RSIMidPointHijackXAUUSD/main.mq5 deleted file mode 100644 index de9ddb3..0000000 --- a/frontline/cluster-fuck/RSIMidPointHijackXAUUSD/main.mq5 +++ /dev/null @@ -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 -#include -#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); -} diff --git a/frontline/cluster-fuck/RSIMidPointHijackXAUUSD/report.html b/frontline/cluster-fuck/RSIMidPointHijackXAUUSD/report.html deleted file mode 100644 index a731713..0000000 Binary files a/frontline/cluster-fuck/RSIMidPointHijackXAUUSD/report.html and /dev/null differ diff --git a/frontline/cluster-fuck/RSIMidPointHijackXAUUSD/report.png b/frontline/cluster-fuck/RSIMidPointHijackXAUUSD/report.png deleted file mode 100644 index 71b2983..0000000 Binary files a/frontline/cluster-fuck/RSIMidPointHijackXAUUSD/report.png and /dev/null differ diff --git a/frontline/cluster-fuck/RSIReversalAsianEURUSD/main.mq5 b/frontline/cluster-fuck/RSIReversalAsianEURUSD/main.mq5 deleted file mode 100644 index c89b331..0000000 --- a/frontline/cluster-fuck/RSIReversalAsianEURUSD/main.mq5 +++ /dev/null @@ -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 - -// 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; - } - } - } -} \ No newline at end of file diff --git a/frontline/cluster-fuck/RSIReversalAsianEURUSD/test-balance.jpg b/frontline/cluster-fuck/RSIReversalAsianEURUSD/test-balance.jpg deleted file mode 100644 index 2901f4b..0000000 Binary files a/frontline/cluster-fuck/RSIReversalAsianEURUSD/test-balance.jpg and /dev/null differ diff --git a/frontline/cluster-fuck/RSIScalpingBTCUSD-trailing/main.mq5 b/frontline/cluster-fuck/RSIScalpingBTCUSD-trailing/main.mq5 deleted file mode 100644 index b34e0a2..0000000 --- a/frontline/cluster-fuck/RSIScalpingBTCUSD-trailing/main.mq5 +++ /dev/null @@ -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 -#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(); - } - } -} diff --git a/frontline/cluster-fuck/RSIScalpingBTCUSD-trailing/report.html b/frontline/cluster-fuck/RSIScalpingBTCUSD-trailing/report.html deleted file mode 100644 index b512b3d..0000000 Binary files a/frontline/cluster-fuck/RSIScalpingBTCUSD-trailing/report.html and /dev/null differ diff --git a/frontline/cluster-fuck/RSIScalpingBTCUSD-trailing/report.png b/frontline/cluster-fuck/RSIScalpingBTCUSD-trailing/report.png deleted file mode 100644 index 52287c6..0000000 Binary files a/frontline/cluster-fuck/RSIScalpingBTCUSD-trailing/report.png and /dev/null differ diff --git a/frontline/cluster-fuck/RSIScalpingXAUUSD-trailing/123.set b/frontline/cluster-fuck/RSIScalpingXAUUSD-trailing/123.set deleted file mode 100644 index 0c7f7c1..0000000 --- a/frontline/cluster-fuck/RSIScalpingXAUUSD-trailing/123.set +++ /dev/null @@ -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 diff --git a/frontline/cluster-fuck/RSIScalpingXAUUSD-trailing/main.mq5 b/frontline/cluster-fuck/RSIScalpingXAUUSD-trailing/main.mq5 deleted file mode 100644 index 96b6f2f..0000000 --- a/frontline/cluster-fuck/RSIScalpingXAUUSD-trailing/main.mq5 +++ /dev/null @@ -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 -#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()); -} diff --git a/frontline/cluster-fuck/RSI_secret_sauce_XAUUSD/main.mq5 b/frontline/cluster-fuck/RSI_secret_sauce_XAUUSD/main.mq5 deleted file mode 100644 index 425b7f7..0000000 --- a/frontline/cluster-fuck/RSI_secret_sauce_XAUUSD/main.mq5 +++ /dev/null @@ -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 -#include - -//--- 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 -} - -//+------------------------------------------------------------------+ diff --git a/frontline/cluster-fuck/SimpleTrendlineBTCUSD/SimpleTrendline.mq5 b/frontline/cluster-fuck/SimpleTrendlineBTCUSD/SimpleTrendline.mq5 deleted file mode 100644 index 6476f77..0000000 --- a/frontline/cluster-fuck/SimpleTrendlineBTCUSD/SimpleTrendline.mq5 +++ /dev/null @@ -1,284 +0,0 @@ -#property strict -#property version "1.00" - -#include - -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 ×[], 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); -} diff --git a/frontline/cluster-fuck/SimpleTrendlineBTCUSD/SimpleTrendline_optimization.set b/frontline/cluster-fuck/SimpleTrendlineBTCUSD/SimpleTrendline_optimization.set deleted file mode 100644 index 10ea2ee..0000000 --- a/frontline/cluster-fuck/SimpleTrendlineBTCUSD/SimpleTrendline_optimization.set +++ /dev/null @@ -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 diff --git a/frontline/cluster-fuck/SimpleTrendlineGER40/SimpleTrendline.mq5 b/frontline/cluster-fuck/SimpleTrendlineGER40/SimpleTrendline.mq5 deleted file mode 100644 index c87c3ef..0000000 --- a/frontline/cluster-fuck/SimpleTrendlineGER40/SimpleTrendline.mq5 +++ /dev/null @@ -1,284 +0,0 @@ -#property strict -#property version "1.00" - -#include - -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 ×[], 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); -} diff --git a/frontline/cluster-fuck/SimpleTrendlineGER40/SimpleTrendline_optimization.set b/frontline/cluster-fuck/SimpleTrendlineGER40/SimpleTrendline_optimization.set deleted file mode 100644 index 10ea2ee..0000000 --- a/frontline/cluster-fuck/SimpleTrendlineGER40/SimpleTrendline_optimization.set +++ /dev/null @@ -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 diff --git a/frontline/cluster-fuck/SimpleTrendlineXAUUSD/SimpleTrendline.mq5 b/frontline/cluster-fuck/SimpleTrendlineXAUUSD/SimpleTrendline.mq5 deleted file mode 100644 index 77ed295..0000000 --- a/frontline/cluster-fuck/SimpleTrendlineXAUUSD/SimpleTrendline.mq5 +++ /dev/null @@ -1,376 +0,0 @@ -#property strict -#property version "1.00" - -#include - -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 ×[], 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); -} diff --git a/frontline/cluster-fuck/SimpleTrendlineXAUUSD/SimpleTrendline_optimization.set b/frontline/cluster-fuck/SimpleTrendlineXAUUSD/SimpleTrendline_optimization.set deleted file mode 100644 index 10ea2ee..0000000 --- a/frontline/cluster-fuck/SimpleTrendlineXAUUSD/SimpleTrendline_optimization.set +++ /dev/null @@ -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 diff --git a/frontline/cluster-gold/MagicNumberHelpers.mqh b/frontline/cluster-gold/MagicNumberHelpers.mqh deleted file mode 100644 index 0423cc4..0000000 --- a/frontline/cluster-gold/MagicNumberHelpers.mqh +++ /dev/null @@ -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); -} - -//+------------------------------------------------------------------+ diff --git a/frontline/cluster-gold/STRATEGY_CONFIGURATION.md b/frontline/cluster-gold/STRATEGY_CONFIGURATION.md deleted file mode 100644 index 799c760..0000000 --- a/frontline/cluster-gold/STRATEGY_CONFIGURATION.md +++ /dev/null @@ -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") diff --git a/frontline/cluster-gold/Strategies/DarvasBoxStrategy.mqh b/frontline/cluster-gold/Strategies/DarvasBoxStrategy.mqh deleted file mode 100644 index 989dc21..0000000 --- a/frontline/cluster-gold/Strategies/DarvasBoxStrategy.mqh +++ /dev/null @@ -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"); -} - -//+------------------------------------------------------------------+ diff --git a/frontline/cluster-gold/Strategies/EMASlopeDistanceStrategy.mqh b/frontline/cluster-gold/Strategies/EMASlopeDistanceStrategy.mqh deleted file mode 100644 index 2ddbeeb..0000000 --- a/frontline/cluster-gold/Strategies/EMASlopeDistanceStrategy.mqh +++ /dev/null @@ -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(); -} - -//+------------------------------------------------------------------+ diff --git a/frontline/cluster-gold/Strategies/RSIConsolidationStrategy.mqh b/frontline/cluster-gold/Strategies/RSIConsolidationStrategy.mqh deleted file mode 100644 index c996950..0000000 --- a/frontline/cluster-gold/Strategies/RSIConsolidationStrategy.mqh +++ /dev/null @@ -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 diff --git a/frontline/cluster-gold/Strategies/RSICrossOverReversalStrategy.mqh b/frontline/cluster-gold/Strategies/RSICrossOverReversalStrategy.mqh deleted file mode 100644 index ddc5f5a..0000000 --- a/frontline/cluster-gold/Strategies/RSICrossOverReversalStrategy.mqh +++ /dev/null @@ -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; -} - -//+------------------------------------------------------------------+ diff --git a/frontline/cluster-gold/Strategies/RSIMidPointHijackStrategy.mqh b/frontline/cluster-gold/Strategies/RSIMidPointHijackStrategy.mqh deleted file mode 100644 index 120996b..0000000 --- a/frontline/cluster-gold/Strategies/RSIMidPointHijackStrategy.mqh +++ /dev/null @@ -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); -} - -//+------------------------------------------------------------------+ diff --git a/frontline/cluster-gold/Strategies/RSIReversalAsianStrategy.mqh b/frontline/cluster-gold/Strategies/RSIReversalAsianStrategy.mqh deleted file mode 100644 index e204fb0..0000000 --- a/frontline/cluster-gold/Strategies/RSIReversalAsianStrategy.mqh +++ /dev/null @@ -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; - } - } - } -} diff --git a/frontline/cluster-gold/Strategies/RSIScalpingStrategy.mqh b/frontline/cluster-gold/Strategies/RSIScalpingStrategy.mqh deleted file mode 100644 index 630955d..0000000 --- a/frontline/cluster-gold/Strategies/RSIScalpingStrategy.mqh +++ /dev/null @@ -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); - } -} - -//+------------------------------------------------------------------+ diff --git a/frontline/cluster-gold/Strategies/RSISecretSauceStrategy.mqh b/frontline/cluster-gold/Strategies/RSISecretSauceStrategy.mqh deleted file mode 100644 index a8c284e..0000000 --- a/frontline/cluster-gold/Strategies/RSISecretSauceStrategy.mqh +++ /dev/null @@ -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 -#include - -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 diff --git a/frontline/cluster-gold/Strategies/SimpleTrendlineStrategy.mqh b/frontline/cluster-gold/Strategies/SimpleTrendlineStrategy.mqh deleted file mode 100644 index 6341b88..0000000 --- a/frontline/cluster-gold/Strategies/SimpleTrendlineStrategy.mqh +++ /dev/null @@ -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 ×[], 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 diff --git a/frontline/cluster-gold/Strategies/SuperEMAStrategy.mqh b/frontline/cluster-gold/Strategies/SuperEMAStrategy.mqh deleted file mode 100644 index 52400fe..0000000 --- a/frontline/cluster-gold/Strategies/SuperEMAStrategy.mqh +++ /dev/null @@ -1,509 +0,0 @@ -//+------------------------------------------------------------------+ -//| SuperEMAStrategy.mqh — EMA + CCI + MACD (United EA module) | -//+------------------------------------------------------------------+ -#ifndef SUPER_EMA_STRATEGY_MQH -#define SUPER_EMA_STRATEGY_MQH - -#include - -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 diff --git a/frontline/cluster-gold/main.mq5 b/frontline/cluster-gold/main.mq5 deleted file mode 100644 index f77c907..0000000 --- a/frontline/cluster-gold/main.mq5 +++ /dev/null @@ -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 -#include -#include -#include -#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); -} - -//+------------------------------------------------------------------+ diff --git a/frontline/cluster-gold/report.png b/frontline/cluster-gold/report.png deleted file mode 100644 index a174d73..0000000 Binary files a/frontline/cluster-gold/report.png and /dev/null differ diff --git a/frontline/cluster-gold/self-evaluate.mq5 b/frontline/cluster-gold/self-evaluate.mq5 deleted file mode 100644 index 971c874..0000000 --- a/frontline/cluster-gold/self-evaluate.mq5 +++ /dev/null @@ -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 -#include -#include -#include -#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" - -//+------------------------------------------------------------------+ diff --git a/frontline/cluster-fuck/_united-V2/MagicNumberHelpers.mqh b/frontline/cluster-latest/MagicNumberHelpers.mqh similarity index 100% rename from frontline/cluster-fuck/_united-V2/MagicNumberHelpers.mqh rename to frontline/cluster-latest/MagicNumberHelpers.mqh diff --git a/frontline/cluster-fuck/RSIScalpingTSLA-trailing/main.mq5 b/frontline/cluster-latest/RSIScalpingMU/main.mq5 similarity index 67% rename from frontline/cluster-fuck/RSIScalpingTSLA-trailing/main.mq5 rename to frontline/cluster-latest/RSIScalpingMU/main.mq5 index 1648b9a..5c53a5d 100644 --- a/frontline/cluster-fuck/RSIScalpingTSLA-trailing/main.mq5 +++ b/frontline/cluster-latest/RSIScalpingMU/main.mq5 @@ -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 #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; diff --git a/frontline/cluster-latest/RSIScalpingMU/optimization.set b/frontline/cluster-latest/RSIScalpingMU/optimization.set new file mode 100644 index 0000000..5d564c8 Binary files /dev/null and b/frontline/cluster-latest/RSIScalpingMU/optimization.set differ diff --git a/frontline/cluster-fuck/RSIScalpingTSLA-trailing/report.html b/frontline/cluster-latest/RSIScalpingMU/report.html similarity index 100% rename from frontline/cluster-fuck/RSIScalpingTSLA-trailing/report.html rename to frontline/cluster-latest/RSIScalpingMU/report.html diff --git a/frontline/cluster-fuck/RSIScalpingTSLA-trailing/report.png b/frontline/cluster-latest/RSIScalpingMU/report.png similarity index 100% rename from frontline/cluster-fuck/RSIScalpingTSLA-trailing/report.png rename to frontline/cluster-latest/RSIScalpingMU/report.png diff --git a/frontline/cluster-fuck/_united-V2/STRATEGY_CONFIGURATION.md b/frontline/cluster-latest/STRATEGY_CONFIGURATION.md similarity index 100% rename from frontline/cluster-fuck/_united-V2/STRATEGY_CONFIGURATION.md rename to frontline/cluster-latest/STRATEGY_CONFIGURATION.md diff --git a/frontline/cluster-fuck/_united-V2/Strategies/DarvasBoxStrategy.mqh b/frontline/cluster-latest/Strategies/DarvasBoxStrategy.mqh similarity index 100% rename from frontline/cluster-fuck/_united-V2/Strategies/DarvasBoxStrategy.mqh rename to frontline/cluster-latest/Strategies/DarvasBoxStrategy.mqh diff --git a/frontline/cluster-fuck/_united-V2/Strategies/EMASlopeDistanceStrategy.mqh b/frontline/cluster-latest/Strategies/EMASlopeDistanceStrategy.mqh similarity index 100% rename from frontline/cluster-fuck/_united-V2/Strategies/EMASlopeDistanceStrategy.mqh rename to frontline/cluster-latest/Strategies/EMASlopeDistanceStrategy.mqh diff --git a/frontline/cluster-fuck/_united-V2/Strategies/RSIConsolidationStrategy.mqh b/frontline/cluster-latest/Strategies/RSIConsolidationStrategy.mqh similarity index 100% rename from frontline/cluster-fuck/_united-V2/Strategies/RSIConsolidationStrategy.mqh rename to frontline/cluster-latest/Strategies/RSIConsolidationStrategy.mqh diff --git a/frontline/cluster-fuck/_united-V2/Strategies/RSICrossOverReversalStrategy.mqh b/frontline/cluster-latest/Strategies/RSICrossOverReversalStrategy.mqh similarity index 100% rename from frontline/cluster-fuck/_united-V2/Strategies/RSICrossOverReversalStrategy.mqh rename to frontline/cluster-latest/Strategies/RSICrossOverReversalStrategy.mqh diff --git a/frontline/cluster-fuck/_united-V2/Strategies/RSIMidPointHijackStrategy.mqh b/frontline/cluster-latest/Strategies/RSIMidPointHijackStrategy.mqh similarity index 100% rename from frontline/cluster-fuck/_united-V2/Strategies/RSIMidPointHijackStrategy.mqh rename to frontline/cluster-latest/Strategies/RSIMidPointHijackStrategy.mqh diff --git a/frontline/cluster-fuck/_united-V2/Strategies/RSIReversalAsianStrategy.mqh b/frontline/cluster-latest/Strategies/RSIReversalAsianStrategy.mqh similarity index 100% rename from frontline/cluster-fuck/_united-V2/Strategies/RSIReversalAsianStrategy.mqh rename to frontline/cluster-latest/Strategies/RSIReversalAsianStrategy.mqh diff --git a/frontline/cluster-fuck/_united-V2/Strategies/RSIScalpingStrategy.mqh b/frontline/cluster-latest/Strategies/RSIScalpingStrategy.mqh similarity index 100% rename from frontline/cluster-fuck/_united-V2/Strategies/RSIScalpingStrategy.mqh rename to frontline/cluster-latest/Strategies/RSIScalpingStrategy.mqh diff --git a/frontline/cluster-fuck/_united-V2/Strategies/RSISecretSauceStrategy.mqh b/frontline/cluster-latest/Strategies/RSISecretSauceStrategy.mqh similarity index 100% rename from frontline/cluster-fuck/_united-V2/Strategies/RSISecretSauceStrategy.mqh rename to frontline/cluster-latest/Strategies/RSISecretSauceStrategy.mqh diff --git a/frontline/cluster-fuck/_united-V2/Strategies/SimpleTrendlineStrategy.mqh b/frontline/cluster-latest/Strategies/SimpleTrendlineStrategy.mqh similarity index 100% rename from frontline/cluster-fuck/_united-V2/Strategies/SimpleTrendlineStrategy.mqh rename to frontline/cluster-latest/Strategies/SimpleTrendlineStrategy.mqh diff --git a/frontline/cluster-fuck/_united-V2/Strategies/SuperEMAStrategy.mqh b/frontline/cluster-latest/Strategies/SuperEMAStrategy.mqh similarity index 100% rename from frontline/cluster-fuck/_united-V2/Strategies/SuperEMAStrategy.mqh rename to frontline/cluster-latest/Strategies/SuperEMAStrategy.mqh diff --git a/frontline/cluster-fuck/_united-V2/main.mq5 b/frontline/cluster-latest/main.mq5 similarity index 93% rename from frontline/cluster-fuck/_united-V2/main.mq5 rename to frontline/cluster-latest/main.mq5 index 0881584..d111220 100644 --- a/frontline/cluster-fuck/_united-V2/main.mq5 +++ b/frontline/cluster-latest/main.mq5 @@ -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); diff --git a/frontline/cluster-fuck/_united-V2/report.png b/frontline/cluster-latest/report.png similarity index 100% rename from frontline/cluster-fuck/_united-V2/report.png rename to frontline/cluster-latest/report.png diff --git a/frontline/cluster-fuck/_united-V2/self-evaluate.mq5 b/frontline/cluster-latest/self-evaluate.mq5 similarity index 100% rename from frontline/cluster-fuck/_united-V2/self-evaluate.mq5 rename to frontline/cluster-latest/self-evaluate.mq5 diff --git a/frontline/united_template/v2-300U.set b/frontline/united_template/v2-300U.set new file mode 100644 index 0000000..db21785 Binary files /dev/null and b/frontline/united_template/v2-300U.set differ diff --git a/frontline/united_template/v2-reserved.set b/frontline/united_template/v2-reserved.set new file mode 100644 index 0000000..81d6d33 Binary files /dev/null and b/frontline/united_template/v2-reserved.set differ diff --git a/frontline/cluster-fuck/RSIScalpingNVDA-trailing/NVDA_Genetic_Optimization.set b/frontline/units-trailing/RSIScalpingNVDA-trailing-V2/NVDA_Genetic_Optimization.set similarity index 74% rename from frontline/cluster-fuck/RSIScalpingNVDA-trailing/NVDA_Genetic_Optimization.set rename to frontline/units-trailing/RSIScalpingNVDA-trailing-V2/NVDA_Genetic_Optimization.set index 81b89e6..4756926 100644 --- a/frontline/cluster-fuck/RSIScalpingNVDA-trailing/NVDA_Genetic_Optimization.set +++ b/frontline/units-trailing/RSIScalpingNVDA-trailing-V2/NVDA_Genetic_Optimization.set @@ -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 diff --git a/frontline/cluster-fuck/RSIScalpingNVDA-trailing/NVDA_Genetic_Optimization_Alternative.set b/frontline/units-trailing/RSIScalpingNVDA-trailing-V2/NVDA_Genetic_Optimization_Alternative.set similarity index 67% rename from frontline/cluster-fuck/RSIScalpingNVDA-trailing/NVDA_Genetic_Optimization_Alternative.set rename to frontline/units-trailing/RSIScalpingNVDA-trailing-V2/NVDA_Genetic_Optimization_Alternative.set index 3fca2be..998ef53 100644 --- a/frontline/cluster-fuck/RSIScalpingNVDA-trailing/NVDA_Genetic_Optimization_Alternative.set +++ b/frontline/units-trailing/RSIScalpingNVDA-trailing-V2/NVDA_Genetic_Optimization_Alternative.set @@ -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 diff --git a/frontline/cluster-fuck/RSIScalpingNVDA-trailing/OPTIMIZATION_GUIDE.md b/frontline/units-trailing/RSIScalpingNVDA-trailing-V2/OPTIMIZATION_GUIDE.md similarity index 100% rename from frontline/cluster-fuck/RSIScalpingNVDA-trailing/OPTIMIZATION_GUIDE.md rename to frontline/units-trailing/RSIScalpingNVDA-trailing-V2/OPTIMIZATION_GUIDE.md diff --git a/frontline/cluster-fuck/RSIScalpingNVDA-trailing/main.mq5 b/frontline/units-trailing/RSIScalpingNVDA-trailing-V2/main.mq5 similarity index 90% rename from frontline/cluster-fuck/RSIScalpingNVDA-trailing/main.mq5 rename to frontline/units-trailing/RSIScalpingNVDA-trailing-V2/main.mq5 index 5950bce..a95b16d 100644 --- a/frontline/cluster-fuck/RSIScalpingNVDA-trailing/main.mq5 +++ b/frontline/units-trailing/RSIScalpingNVDA-trailing-V2/main.mq5 @@ -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 #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) { diff --git a/frontline/units/EMASlopeDistanceCocktailXAUUSD/EMASlopeDistanceCocktailXAUUSD_Genetic_Optimization.set b/frontline/units/EMASlopeDistanceCocktailXAUUSD/EMASlopeDistanceCocktailXAUUSD_Genetic_Optimization.set new file mode 100644 index 0000000..8e9725e --- /dev/null +++ b/frontline/units/EMASlopeDistanceCocktailXAUUSD/EMASlopeDistanceCocktailXAUUSD_Genetic_Optimization.set @@ -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 diff --git a/frontline/units/EMASlopeDistanceCocktailXAUUSD/main.mq5 b/frontline/units/EMASlopeDistanceCocktailXAUUSD/main.mq5 index 06b1086..586e17e 100644 --- a/frontline/units/EMASlopeDistanceCocktailXAUUSD/main.mq5 +++ b/frontline/units/EMASlopeDistanceCocktailXAUUSD/main.mq5 @@ -8,24 +8,24 @@ #property version "1.00" #include #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) diff --git a/frontline/units/RSIConsolidationXAUUSD/RSIConsolidation.mq5 b/frontline/units/RSIConsolidationXAUUSD/RSIConsolidation.mq5 deleted file mode 100644 index 09c4d7d..0000000 --- a/frontline/units/RSIConsolidationXAUUSD/RSIConsolidation.mq5 +++ /dev/null @@ -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 - -//--- 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"); - } -} - -//+------------------------------------------------------------------+ diff --git a/frontline/units/RSIConsolidationXAUUSD/RSIConsolidation_optimization.set b/frontline/units/RSIConsolidationXAUUSD/RSIConsolidation_optimization.set deleted file mode 100644 index d6a75ed..0000000 --- a/frontline/units/RSIConsolidationXAUUSD/RSIConsolidation_optimization.set +++ /dev/null @@ -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 diff --git a/frontline/units/RSICrossOverReversalXAUUSD/RSICrossOverReversalXAUUSD_Genetic_Optimization.set b/frontline/units/RSICrossOverReversalXAUUSD/RSICrossOverReversalXAUUSD_Genetic_Optimization.set new file mode 100644 index 0000000..ac331d4 --- /dev/null +++ b/frontline/units/RSICrossOverReversalXAUUSD/RSICrossOverReversalXAUUSD_Genetic_Optimization.set @@ -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 diff --git a/frontline/units/RSIMidPointHijackXAUUSD/RSIMidPointHijackXAUUSD_Genetic_Optimization.set b/frontline/units/RSIMidPointHijackXAUUSD/RSIMidPointHijackXAUUSD_Genetic_Optimization.set new file mode 100644 index 0000000..73379c5 --- /dev/null +++ b/frontline/units/RSIMidPointHijackXAUUSD/RSIMidPointHijackXAUUSD_Genetic_Optimization.set @@ -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 diff --git a/frontline/units/RSIReversalAsianAUDUSD/RSIReversalAsianAUDUSD_Genetic_Optimization.set b/frontline/units/RSIReversalAsianAUDUSD/RSIReversalAsianAUDUSD_Genetic_Optimization.set new file mode 100644 index 0000000..9fbe5fe --- /dev/null +++ b/frontline/units/RSIReversalAsianAUDUSD/RSIReversalAsianAUDUSD_Genetic_Optimization.set @@ -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 diff --git a/frontline/units/RSIReversalAsianGBPUSD/RSIReversalAsianAUDUSD_Genetic_Optimization.set b/frontline/units/RSIReversalAsianGBPUSD/RSIReversalAsianAUDUSD_Genetic_Optimization.set new file mode 100644 index 0000000..9fbe5fe --- /dev/null +++ b/frontline/units/RSIReversalAsianGBPUSD/RSIReversalAsianAUDUSD_Genetic_Optimization.set @@ -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 diff --git a/frontline/cluster-fuck/RSIReversalAsianAUDUSD/main.mq5 b/frontline/units/RSIReversalAsianGBPUSD/main.mq5 similarity index 96% rename from frontline/cluster-fuck/RSIReversalAsianAUDUSD/main.mq5 rename to frontline/units/RSIReversalAsianGBPUSD/main.mq5 index 92c7968..6ac07bd 100644 --- a/frontline/cluster-fuck/RSIReversalAsianAUDUSD/main.mq5 +++ b/frontline/units/RSIReversalAsianGBPUSD/main.mq5 @@ -1,5 +1,5 @@ //+------------------------------------------------------------------+ -//| SimpleRSIReversalAUDUSD.mq5 | +//| RSIReversalAsianGBPUSD.mq5 | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ @@ -11,19 +11,19 @@ // Include trade class #include -// 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 diff --git a/frontline/cluster-fuck/RSIReversalAsianAUDUSD/test-balance.png b/frontline/units/RSIReversalAsianGBPUSD/test-balance.png similarity index 100% rename from frontline/cluster-fuck/RSIReversalAsianAUDUSD/test-balance.png rename to frontline/units/RSIReversalAsianGBPUSD/test-balance.png diff --git a/frontline/units/RSIScalpingMU/main.mq5 b/frontline/units/RSIScalpingMU/main.mq5 new file mode 100644 index 0000000..5c53a5d --- /dev/null +++ b/frontline/units/RSIScalpingMU/main.mq5 @@ -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 +#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; + } +} diff --git a/frontline/units/RSIScalpingMU/optimization.set b/frontline/units/RSIScalpingMU/optimization.set new file mode 100644 index 0000000..5d564c8 Binary files /dev/null and b/frontline/units/RSIScalpingMU/optimization.set differ diff --git a/frontline/units/RSIScalpingMU/report.html b/frontline/units/RSIScalpingMU/report.html new file mode 100644 index 0000000..950f95b Binary files /dev/null and b/frontline/units/RSIScalpingMU/report.html differ diff --git a/frontline/units/RSIScalpingMU/report.png b/frontline/units/RSIScalpingMU/report.png new file mode 100644 index 0000000..5a26c1d Binary files /dev/null and b/frontline/units/RSIScalpingMU/report.png differ diff --git a/frontline/units/RSIScalpingNVDA/main.mq5 b/frontline/units/RSIScalpingNVDA/main.mq5 index 74b2310..173bfec 100644 --- a/frontline/units/RSIScalpingNVDA/main.mq5 +++ b/frontline/units/RSIScalpingNVDA/main.mq5 @@ -10,17 +10,17 @@ #include #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 diff --git a/frontline/units/RSIScalpingTSLA/main.mq5 b/frontline/units/RSIScalpingTSLA/main.mq5 index 66897e9..5c53a5d 100644 --- a/frontline/units/RSIScalpingTSLA/main.mq5 +++ b/frontline/units/RSIScalpingTSLA/main.mq5 @@ -10,17 +10,17 @@ #include #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 diff --git a/frontline/units/RSIScalpingXAUUSD/report.html b/frontline/units/RSIScalpingXAUUSD/report.html deleted file mode 100644 index 203dcf4..0000000 Binary files a/frontline/units/RSIScalpingXAUUSD/report.html and /dev/null differ diff --git a/frontline/units/RSIScalpingXAUUSD/report.png b/frontline/units/RSIScalpingXAUUSD/report.png deleted file mode 100644 index c2c91f2..0000000 Binary files a/frontline/units/RSIScalpingXAUUSD/report.png and /dev/null differ diff --git a/frontline/units/SuperEMAXAUUSD/SuperEMA.set b/frontline/units/SuperEMAXAUUSD/SuperEMA.set deleted file mode 100644 index f52ec17..0000000 --- a/frontline/units/SuperEMAXAUUSD/SuperEMA.set +++ /dev/null @@ -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 diff --git a/frontline/units/SuperEMAXAUUSD/main.mq5 b/frontline/units/SuperEMAXAUUSD/main.mq5 deleted file mode 100644 index 07831c3..0000000 --- a/frontline/units/SuperEMAXAUUSD/main.mq5 +++ /dev/null @@ -1,448 +0,0 @@ -//+------------------------------------------------------------------+ -//| SuperEMA.mq5 | -//| EMA + CCI + MACD histogram — trend filter, momentum confirmation | -//+------------------------------------------------------------------+ -#property strict -#property version "1.01" - -#include - -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)); - } -} diff --git a/lab/EAs/CandleChartPattern/CandleChartPattern_Genetic_Optimization.set b/lab/EAs/CandleChartPattern/CandleChartPattern_Genetic_Optimization.set new file mode 100644 index 0000000..86c6f65 --- /dev/null +++ b/lab/EAs/CandleChartPattern/CandleChartPattern_Genetic_Optimization.set @@ -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 diff --git a/lab/EAs/CandleChartPattern/main.mq5 b/lab/EAs/CandleChartPattern/main.mq5 new file mode 100644 index 0000000..2048753 --- /dev/null +++ b/lab/EAs/CandleChartPattern/main.mq5 @@ -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 + +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"); + } +} diff --git a/lab/EAs/Derivative.mq5 b/lab/EAs/Derivative.mq5 new file mode 100644 index 0000000..eed4ffc --- /dev/null +++ b/lab/EAs/Derivative.mq5 @@ -0,0 +1,1582 @@ +//+------------------------------------------------------------------+ + +//| Derivative.mq5 | + +//| EA: finite-difference d1–d3 of price + optional demo signals | + +//| (Former indicator — attach as Expert Advisor on chart.) | + +//+------------------------------------------------------------------+ + +#property copyright "Lab" + +#property link "" + +#property version "3.00" + +#property strict + +#include + +#include + +#property description "DERIVATIVE_CALC EA v3 — derivatives + optional trades; canvas strip or legacy DerivativePlots." + +#property description "Canvas mode draws d1/d2/d3 at bottom without indicators; legacy mode optional." + +enum ENUM_DERIVATIVE_VIEW + +{ + + DERIVATIVE_ALL = 0, + + DERIVATIVE_LEVEL_1 = 1, + + DERIVATIVE_LEVEL_2 = 2, + + DERIVATIVE_LEVEL_3 = 3 + +}; + +input group "=== Instrument ===" + +input string InpSymbol = ""; // blank = chart symbol + +input group "=== Series ===" + +input ENUM_TIMEFRAMES InpSignalTF = PERIOD_CURRENT; // PERIOD_CURRENT = chart TF + +input ENUM_APPLIED_PRICE InpAppliedPrice = PRICE_CLOSE; + +input group "=== Layout (reporting focus) ===" + +input ENUM_DERIVATIVE_VIEW InpWhichDerivative = DERIVATIVE_ALL; // Which values drive Comment / optional trade filter + +input group "=== Calculus discretization ===" + +input int InpDiffStep = 1; + +input bool InpNormalizePoints = true; + +input group "=== Smoothing ===" + +input int InpSmoothPeriod = 0; + +input group "=== On-chart guide (labels on main window) ===" + +input bool InpShowHelpPanel = true; + +input color InpHelpTitleColor = clrWhite; + +input color InpHelpBodyColor = clrSilver; + +input group "=== Display ===" + +input bool InpShowComment = true; // Status line + d1/d2/d3 on chart + +input int InpCommentThrottleMs = 200; // Min real-time ms between Comment() calls (0=off). Visual tester floods redraws without this. + +input bool InpDebugTrace = false; // Experts/Journal: derivatives + attach diagnostics + +input group "=== Canvas strip (EA draws d1/d2/d3 — no indicator .ex5) ===" + +input bool InpUseCanvasPlots = true; // Three stacked strips at bottom (bitmap on main window) + +input int InpCanvasPlotBars = 320; // Bars across width (series 0 = current) + +input int InpCanvasPanelHeight = 210; // Total pixel height for three strips + +input int InpCanvasBottomMargin = 28; // From chart bottom (CORNER_LEFT_LOWER) + +input int InpCanvasSideMargin = 4; // Left/right inset + +input int InpCanvasRedrawMs = 350; // Min ms between canvas rebuilds + +input color InpCanvasBgColor = clrBlack; + +input color InpCanvasGridColor = clrDimGray; + +input group "=== Legacy: DerivativePlots indicator (optional) ===" + +input bool InpAutoAttachDerivativePlots = false; // Requires DerivativePlots.ex5 in Indicators + +input bool InpAttachPlotsInTester = false; // Non-visual tester: set true if .ex5 present + +input string InpPlotsIndicatorPath = "DerivativePlots"; // .ex5 basename in Indicators folder + +input bool InpPlotsSeparateWindows = false; // Three iCustom instances + stacked subwindows + +input bool InpPlotsUnifyYScale = true; // DerivativePlots InpUnifyPlotYScale + +input group "=== Optional demo trading (off by default) ===" + +input bool InpTradeEnabled = false; + +input double InpLots = 0.01; + +input ulong InpMagic = 931001; + +input int InpSlippagePoints = 30; + +input int InpAtrPeriod = 14; + +input double InpSlAtrMult = 2.0; + +input double InpTpAtrMult = 3.0; + +CTrade g_trade; + +datetime g_lastBarTime = 0; + +string g_chartSymbol = ""; + +bool g_pendingDerivativePlotsAttach = false; + +bool g_derivativePlotsFailedToLoad = false; + +bool g_derivPlotsAttachDone = false; + +uint g_lastCommentWallMs = 0; + +CCanvas g_deriv_canvas; + +bool g_deriv_canvas_created = false; + +uint g_lastCanvasRedrawMs = 0; + +const string HELPER_FAMILY = "DerivRead"; + +const string DERIV_CANVAS_OBJ = "DerivEA_CanvasStrip_v3"; + +void CommentThrottled(const string text) + +{ + + if(InpCommentThrottleMs <= 0) + + { + + Comment(text); + + return; + + } + + const uint now = GetTickCount(); + + if(g_lastCommentWallMs != 0 && (now - g_lastCommentWallMs) < (uint)InpCommentThrottleMs) + + return; + + g_lastCommentWallMs = now; + + Comment(text); + +} + +string DerivativePlotsMissingHint() + +{ + + if(!g_derivativePlotsFailedToLoad || !InpAutoAttachDerivativePlots) + + return ""; + + const string want = TerminalInfoString(TERMINAL_DATA_PATH) + "\\MQL5\\Indicators\\" + InpPlotsIndicatorPath + ".ex5"; + + return "\n--- DerivativePlots NOT loaded ---\nPlace compiled file:\n" + want + + + "\n(Navigator: Indicators -> right-click -> Open folder -> paste .mq5, Compile.)"; + +} + +string HelpPrefix() + +{ + + return HELPER_FAMILY + "_EA_L" + IntegerToString((int)InpWhichDerivative) + "_"; + +} + +void DeleteOurHelpObjects() + +{ + + const string px = HelpPrefix(); + + ObjectDelete(0, px + "title"); + + ObjectDelete(0, px + "body"); + + ObjectDelete(0, px + "interp"); + +} + +bool LabelCreateMain(const string name, const int corner, const int xd, const int yd, + + const string text, const color clr, const int fontSize, const int anchor) + +{ + + if(!ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0)) + + return false; + + ObjectSetInteger(0, name, OBJPROP_CORNER, corner); + + ObjectSetInteger(0, name, OBJPROP_ANCHOR, anchor); + + ObjectSetInteger(0, name, OBJPROP_XDISTANCE, xd); + + ObjectSetInteger(0, name, OBJPROP_YDISTANCE, yd); + + ObjectSetString(0, name, OBJPROP_TEXT, text); + + ObjectSetInteger(0, name, OBJPROP_COLOR, clr); + + ObjectSetInteger(0, name, OBJPROP_FONTSIZE, fontSize); + + ObjectSetString(0, name, OBJPROP_FONT, "Consolas"); + + ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false); + + ObjectSetInteger(0, name, OBJPROP_HIDDEN, true); + + return true; + +} + +void TryBuildHelpPanel() + +{ + + if(!InpShowHelpPanel) + + { + + DeleteOurHelpObjects(); + + return; + + } + + const string px = HelpPrefix(); + + ObjectDelete(0, px + "title"); + + ObjectDelete(0, px + "body"); + + ObjectDelete(0, px + "interp"); + + const int x0 = 8; + + string title = "DERIVATIVE_CALC EA — readout\n"; + + string body = ""; + + string interp = ""; + + if(InpWhichDerivative == DERIVATIVE_ALL) + + { + + body = + + "d1 = slope of price / step h (velocity)\n" + + "d2 = change of d1 (acceleration)\n" + + "d3 = change of d2 (jerk)\n" + + "See Experts log + Comment line for numbers."; + + interp = "Optional demo trades use Which derivative + sign rules (inputs)."; + + } + + else if(InpWhichDerivative == DERIVATIVE_LEVEL_1) + + { + + title = "EA focus: d1 only\n"; + + body = "d1 > 0 : rising over h bars; < 0 falling; cross 0 : flip."; + + interp = "Demo buy bias if d1>0 & d2>0 when trade enabled."; + + } + + else if(InpWhichDerivative == DERIVATIVE_LEVEL_2) + + { + + title = "EA focus: d2 only\n"; + + body = "d2 : momentum building (+) or fading (-) vs d1."; + + interp = "Use with price context."; + + } + + else + + { + + title = "EA focus: d3 only\n"; + + body = "d3 : noisy; regime / climax hints."; + + interp = "Large |d3| → acceleration changing fast."; + + } + + if(!LabelCreateMain(px + "title", CORNER_LEFT_UPPER, x0, 20, title, InpHelpTitleColor, 10, ANCHOR_LEFT_UPPER)) + + return; + + if(!LabelCreateMain(px + "body", CORNER_LEFT_UPPER, x0, 42, body, InpHelpBodyColor, 8, ANCHOR_LEFT_UPPER)) + + { + + ObjectDelete(0, px + "title"); + + return; + + } + + if(!LabelCreateMain(px + "interp", CORNER_LEFT_LOWER, x0, 8, interp, InpHelpBodyColor, 8, ANCHOR_LEFT_LOWER)) + + { + + ObjectDelete(0, px + "title"); + + ObjectDelete(0, px + "body"); + + return; + + } + +} + +double AppliedFromRates(const MqlRates &r) + +{ + + switch(InpAppliedPrice) + + { + + case PRICE_OPEN: return r.open; + + case PRICE_HIGH: return r.high; + + case PRICE_LOW: return r.low; + + case PRICE_CLOSE: return r.close; + + case PRICE_MEDIAN: return (r.high + r.low) * 0.5; + + case PRICE_TYPICAL: return (r.high + r.low + r.close) / 3.0; + + case PRICE_WEIGHTED:return (r.high + r.low + r.close + r.close) / 4.0; + + default: return r.close; + + } + +} + +void SmoothPriceArray(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); + + const int oldest = total - 1; + + double ema = src[oldest]; + + dst[oldest] = ema; + + for(int i = oldest - 1; i >= 0; i--) + + { + + ema = alpha * src[i] + (1.0 - alpha) * ema; + + dst[i] = ema; + + } + +} + +double SrcAt(const int i, const bool useSmooth, const double &smooth[], const double &raw[]) + +{ + + return useSmooth ? smooth[i] : raw[i]; + +} + +bool ComputeDerivatives(const string sym, const ENUM_TIMEFRAMES tf, + + double &out_d1, double &out_d2, double &out_d3) + +{ + + out_d1 = out_d2 = out_d3 = 0.0; + + const int h = MathMax(InpDiffStep, 1); + + const int needBars = 50 + h * 6; + + MqlRates rates[]; + + ArraySetAsSeries(rates, true); + + const int n = CopyRates(sym, tf, 0, needBars, rates); + + if(n < h * 3 + 5) + + return false; + + double raw[]; + + ArrayResize(raw, n); + + ArraySetAsSeries(raw, true); + + for(int i = 0; i < n; i++) + + raw[i] = AppliedFromRates(rates[i]); + + double smoothed[]; + + SmoothPriceArray(n, raw, smoothed); + + const bool useSmooth = (InpSmoothPeriod > 1); + + const double scale = InpNormalizePoints ? SymbolInfoDouble(sym, SYMBOL_POINT) : 1.0; + + if(scale <= 0.0) + + return false; + + const int i = 1; + + if(i + h >= n) + + return false; + + const double d1_i = (SrcAt(i, useSmooth, smoothed, raw) - SrcAt(i + h, useSmooth, smoothed, raw)) / ((double)h * scale); + + if(i + 2 * h >= n) + + { + + out_d1 = d1_i; + + return true; + + } + + const double d1_ip = (SrcAt(i + h, useSmooth, smoothed, raw) - SrcAt(i + 2 * h, useSmooth, smoothed, raw)) / ((double)h * scale); + + const double d2_i = (d1_i - d1_ip) / ((double)h * scale); + + if(i + 3 * h >= n) + + { + + out_d1 = d1_i; + + out_d2 = d2_i; + + return true; + + } + + const double d1_ip2 = (SrcAt(i + 2 * h, useSmooth, smoothed, raw) - SrcAt(i + 3 * h, useSmooth, smoothed, raw)) / ((double)h * scale); + + const double d2_ip = (d1_ip - d1_ip2) / ((double)h * scale); + + const double d3_i = (d2_i - d2_ip) / ((double)h * scale); + + out_d1 = d1_i; + + out_d2 = d2_i; + + out_d3 = d3_i; + + return true; + +} + +double CanvasSeriesAt(const int row, const int si, + + const double &d1[], const double &d2[], const double &d3[]) + +{ + + if(row == 0) + + return d1[si]; + + if(row == 1) + + return d2[si]; + + return d3[si]; + +} + +bool ComputeDerivativeSeries(const string sym, const ENUM_TIMEFRAMES tf, + + const int plotBars, + + double &d1[], double &d2[], double &d3[]) + +{ + + const int h = MathMax(InpDiffStep, 1); + + const int need = plotBars + h * 4 + 10; + + MqlRates rates[]; + + ArraySetAsSeries(rates, true); + + const int n = CopyRates(sym, tf, 0, need, rates); + + if(n < h * 3 + 5) + + return false; + + double raw[]; + + ArrayResize(raw, n); + + ArraySetAsSeries(raw, true); + + for(int i = 0; i < n; i++) + + raw[i] = AppliedFromRates(rates[i]); + + double smoothed[]; + + SmoothPriceArray(n, raw, smoothed); + + const bool useSmooth = (InpSmoothPeriod > 1); + + const double scale = InpNormalizePoints ? SymbolInfoDouble(sym, SYMBOL_POINT) : 1.0; + + if(scale <= 0.0) + + return false; + + ArrayResize(d1, plotBars); + + ArrayResize(d2, plotBars); + + ArrayResize(d3, plotBars); + + ArrayInitialize(d1, EMPTY_VALUE); + + ArrayInitialize(d2, EMPTY_VALUE); + + ArrayInitialize(d3, EMPTY_VALUE); + + const int d1Count = MathMin(plotBars, n - h); + + for(int si = 0; si < d1Count; si++) + + d1[si] = (SrcAt(si, useSmooth, smoothed, raw) - SrcAt(si + h, useSmooth, smoothed, raw)) / ((double)h * scale); + + for(int si = 0; si < plotBars; si++) + + { + + if(si + 2 * h >= n || si + h >= d1Count) + + break; + + d2[si] = (d1[si] - d1[si + h]) / ((double)h * scale); + + } + + for(int si = 0; si < plotBars; si++) + + { + + if(si + 3 * h >= n) + + break; + + if(si + h >= plotBars) + + break; + + if(d2[si] == EMPTY_VALUE || d2[si + h] == EMPTY_VALUE) + + continue; + + d3[si] = (d2[si] - d2[si + h]) / ((double)h * scale); + + } + + return true; + +} + +void UpdateDerivativeCanvasStrip() + +{ + + if(!InpUseCanvasPlots) + + return; + + ENUM_TIMEFRAMES tf = InpSignalTF; + + if(tf == PERIOD_CURRENT) + + tf = (ENUM_TIMEFRAMES)Period(); + + double d1[], d2[], d3[]; + + if(!ComputeDerivativeSeries(g_chartSymbol, tf, InpCanvasPlotBars, d1, d2, d3)) + + return; + + const int chartW = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS); + + if(chartW < 80) + + return; + + const int panelW = MathMax(60, chartW - InpCanvasSideMargin * 2); + + const int panelH = MathMax(90, InpCanvasPanelHeight); + + const int x0 = InpCanvasSideMargin; + + const int y0 = InpCanvasBottomMargin; + + if(!g_deriv_canvas_created) + + { + + if(!g_deriv_canvas.CreateBitmapLabel(0, 0, DERIV_CANVAS_OBJ, x0, y0, panelW, panelH, COLOR_FORMAT_ARGB_NORMALIZE)) + + { + + if(InpDebugTrace) + + Print("DERIVATIVE_CALC: canvas CreateBitmapLabel failed err=", GetLastError()); + + return; + + } + + ObjectSetInteger(0, DERIV_CANVAS_OBJ, OBJPROP_CORNER, CORNER_LEFT_LOWER); + + ObjectSetInteger(0, DERIV_CANVAS_OBJ, OBJPROP_ANCHOR, ANCHOR_LEFT_LOWER); + + ObjectSetInteger(0, DERIV_CANVAS_OBJ, OBJPROP_SELECTABLE, false); + + ObjectSetInteger(0, DERIV_CANVAS_OBJ, OBJPROP_HIDDEN, true); + + g_deriv_canvas_created = true; + + } + + else + + { + + g_deriv_canvas.Resize(panelW, panelH); + + ObjectSetInteger(0, DERIV_CANVAS_OBJ, OBJPROP_XDISTANCE, x0); + + ObjectSetInteger(0, DERIV_CANVAS_OBJ, OBJPROP_YDISTANCE, y0); + + } + + g_deriv_canvas.Erase(ColorToARGB(InpCanvasBgColor, 255)); + + const int rows = 3; + + const int rowH = MathMax(24, panelH / rows); + + const uint clrLines[3] = { + + ColorToARGB(clrDodgerBlue, 235), + + ColorToARGB(clrOrange, 235), + + ColorToARGB(clrMagenta, 235) + + }; + + const string tags[3] = { "d1 velocity", "d2 acceleration", "d3 jerk" }; + + const int nPts = MathMin(InpCanvasPlotBars, ArraySize(d1)); + + if(nPts < 3) + + { + + g_deriv_canvas.Update(); + + return; + + } + + for(int r = 0; r < rows; r++) + + { + + const int yBase = r * rowH; + + const int midY = yBase + rowH / 2; + + g_deriv_canvas.LineAA(0.0, (double)midY, (double)(panelW - 1), (double)midY, ColorToARGB(InpCanvasGridColor, 70)); + + double vmin = DBL_MAX; + + double vmax = -DBL_MAX; + + for(int si = 0; si < nPts; si++) + + { + + const double v = CanvasSeriesAt(r, si, d1, d2, d3); + + if(v == EMPTY_VALUE || !MathIsValidNumber(v)) + + continue; + + if(v < vmin) + + vmin = v; + + if(v > vmax) + + vmax = v; + + } + + if(vmin == DBL_MAX) + + continue; + + if(MathAbs(vmax - vmin) < 1e-15) + + { + + vmin -= 1.0; + + vmax += 1.0; + + } + + g_deriv_canvas.FontSet("Consolas", -90); + + g_deriv_canvas.TextOut(4, yBase + 2, tags[r], ColorToARGB(clrSilver, 220)); + + const double denom = (double)MathMax(1, nPts - 1); + + for(int si = 0; si < nPts - 1; si++) + + { + + const double v0 = CanvasSeriesAt(r, si, d1, d2, d3); + + const double v1 = CanvasSeriesAt(r, si + 1, d1, d2, d3); + + if(v0 == EMPTY_VALUE || v1 == EMPTY_VALUE) + + continue; + + const double xf0 = (double)(panelW - 1) * (double)(nPts - 1 - si) / denom; + + const double xf1 = (double)(panelW - 1) * (double)(nPts - 2 - si) / denom; + + const double t0 = (v0 - vmin) / (vmax - vmin); + + const double t1 = (v1 - vmin) / (vmax - vmin); + + const int py0 = yBase + 3 + (int)((double)(rowH - 6) * (1.0 - t0)); + + const int py1 = yBase + 3 + (int)((double)(rowH - 6) * (1.0 - t1)); + + g_deriv_canvas.LineAA(xf0, (double)py0, xf1, (double)py1, clrLines[r]); + + } + + } + + g_deriv_canvas.Update(); + + ChartRedraw(0); + +} + +bool HasOurPosition(const string sym) + +{ + + 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((ulong)PositionGetInteger(POSITION_MAGIC) != InpMagic) + + continue; + + return true; + + } + + return false; + +} + +double AtrPoints(const string sym, const ENUM_TIMEFRAMES tf) + +{ + + const int h = iATR(sym, tf, InpAtrPeriod); + + if(h == INVALID_HANDLE) + + return 0.0; + + double b[]; + + ArraySetAsSeries(b, true); + + if(CopyBuffer(h, 0, 1, 1, b) != 1) + + { + + IndicatorRelease(h); + + return 0.0; + + } + + IndicatorRelease(h); + + const double pt = SymbolInfoDouble(sym, SYMBOL_POINT); + + return (pt > 0.0 ? b[0] / pt : 0.0); + +} + +void RemoveDerivativePlotsIndicatorsFromChart() + +{ + + const int nw = (int)ChartGetInteger(0, CHART_WINDOWS_TOTAL); + + for(int w = nw - 1; w >= 0; w--) + + { + + const int nc = ChartIndicatorsTotal(0, w); + + for(int k = nc - 1; k >= 0; k--) + + { + + const string nm = ChartIndicatorName(0, w, k); + + if(StringFind(nm, "DERIV_") >= 0 || + + StringFind(nm, "DERIV_PLOTS") >= 0 || + + StringFind(nm, InpPlotsIndicatorPath) >= 0 || + + StringFind(nm, "DerivativePlots") >= 0) + + ChartIndicatorDelete(0, w, nm); + + } + + } + +} + +bool DerivativePlotsAlreadyOnChart() + +{ + + const int nw = (int)ChartGetInteger(0, CHART_WINDOWS_TOTAL); + + for(int w = 0; w < nw; w++) + + { + + const int nc = ChartIndicatorsTotal(0, w); + + for(int k = 0; k < nc; k++) + + { + + const string nm = ChartIndicatorName(0, w, k); + + if(StringFind(nm, "DERIV_") >= 0 || StringFind(nm, "DERIV_PLOTS") >= 0 || + + StringFind(nm, InpPlotsIndicatorPath) >= 0) + + return true; + + } + + } + + return false; + +} + +// Pass every DerivativePlots input (same order as .mq5) so each WhichDerivative gets its own handle. + +int MakeDerivativePlotsHandle(const string sym, const ENUM_TIMEFRAMES tf, + + const ENUM_DERIVATIVE_VIEW which, const bool unifyY) + +{ + + return iCustom(sym, tf, InpPlotsIndicatorPath, + + InpAppliedPrice, + + which, + + unifyY, + + InpDiffStep, + + InpNormalizePoints, + + InpSmoothPeriod, + + true, + + InpDebugTrace, + + false); + +} + +bool AttachDerivativePlotsIndicator(const string sym, const ENUM_TIMEFRAMES tf) + +{ + + if(!InpAutoAttachDerivativePlots) + + return false; + + if(g_derivPlotsAttachDone) + + return true; + + const string wantPath = TerminalInfoString(TERMINAL_DATA_PATH) + "\\MQL5\\Indicators\\" + InpPlotsIndicatorPath + ".ex5"; + + // ChartIndicatorAdd(chart, subwindow, handle). Subwindow index: use ChartWindowsTotal() before each add + + // so new panes are appended below existing windows (ATR etc.). Fixed 1,2,3 collides with other indicators. + + const bool unifyPass = InpPlotsSeparateWindows ? false : InpPlotsUnifyYScale; + + if(InpPlotsSeparateWindows) + + { + + ResetLastError(); + + const int ind1 = MakeDerivativePlotsHandle(sym, tf, DERIVATIVE_LEVEL_1, unifyPass); + + if(ind1 == INVALID_HANDLE) + + { + + g_derivativePlotsFailedToLoad = true; + + Print("DERIVATIVE_CALC: iCustom(", InpPlotsIndicatorPath, ", d1) failed err=", GetLastError(), + + ". Required:\n ", wantPath); + + if(InpDebugTrace) + + PrintFormat("DERIVATIVE_CALC dbg iCustom d1 sym=%s tf=%s", sym, EnumToString(tf)); + + return false; + + } + + ResetLastError(); + + const int ind2 = MakeDerivativePlotsHandle(sym, tf, DERIVATIVE_LEVEL_2, unifyPass); + + if(ind2 == INVALID_HANDLE) + + { + + IndicatorRelease(ind1); + + g_derivativePlotsFailedToLoad = true; + + Print("DERIVATIVE_CALC: iCustom(", InpPlotsIndicatorPath, ", d2) failed err=", GetLastError(), + + ". Required:\n ", wantPath); + + return false; + + } + + ResetLastError(); + + const int ind3 = MakeDerivativePlotsHandle(sym, tf, DERIVATIVE_LEVEL_3, unifyPass); + + if(ind3 == INVALID_HANDLE) + + { + + IndicatorRelease(ind1); + + IndicatorRelease(ind2); + + g_derivativePlotsFailedToLoad = true; + + Print("DERIVATIVE_CALC: iCustom(", InpPlotsIndicatorPath, ", d3) failed err=", GetLastError(), + + ". Required:\n ", wantPath); + + return false; + + } + + if(InpDebugTrace) + + PrintFormat("DERIVATIVE_CALC dbg triple iCustom handles ind1=%d ind2=%d ind3=%d (should differ)", + + ind1, ind2, ind3); + + RemoveDerivativePlotsIndicatorsFromChart(); + + int sw = (int)ChartGetInteger(0, CHART_WINDOWS_TOTAL); + + ResetLastError(); + + const bool ok1 = ChartIndicatorAdd(0, sw, ind1); + + const int err1 = GetLastError(); + + sw = (int)ChartGetInteger(0, CHART_WINDOWS_TOTAL); + + ResetLastError(); + + const bool ok2 = ChartIndicatorAdd(0, sw, ind2); + + const int err2 = GetLastError(); + + sw = (int)ChartGetInteger(0, CHART_WINDOWS_TOTAL); + + ResetLastError(); + + const bool ok3 = ChartIndicatorAdd(0, sw, ind3); + + const int err3 = GetLastError(); + + IndicatorRelease(ind1); + + IndicatorRelease(ind2); + + IndicatorRelease(ind3); + + if(!ok1 || !ok2 || !ok3) + + { + + g_derivativePlotsFailedToLoad = true; + + Print("DERIVATIVE_CALC: ChartIndicatorAdd (3 panes) failed ok=", ok1, ",", ok2, ",", ok3, + + " err=", err1, ",", err2, ",", err3, ". File: ", wantPath); + + return false; + + } + + g_derivativePlotsFailedToLoad = false; + + g_derivPlotsAttachDone = true; + + ChartRedraw(0); + + Print("DERIVATIVE_CALC: DerivativePlots attached as three stacked subwindows (indices chosen from CHART_WINDOWS_TOTAL)."); + + if(InpDebugTrace) + + PrintFormat("DERIVATIVE_CALC dbg triple attach OK sym=%s tf=%s", sym, EnumToString(tf)); + + return true; + + } + + ResetLastError(); + + const int ind = MakeDerivativePlotsHandle(sym, tf, InpWhichDerivative, unifyPass); + + if(ind == INVALID_HANDLE) + + { + + g_derivativePlotsFailedToLoad = true; + + Print("DERIVATIVE_CALC: iCustom(\"", InpPlotsIndicatorPath, "\") failed err=", GetLastError(), + + ". MT5 could not read the compiled indicator. Required file:\n ", wantPath, + + "\nCopy lab\\\\EAs\\\\DerivativePlots.mq5 into that Indicators folder, open in MetaEditor, press Compile (F7)."); + + if(InpDebugTrace) + + PrintFormat("DERIVATIVE_CALC dbg iCustom sym=%s tf=%s applied=%d which=%d unify=%s h=%d norm=%s sm=%d", + + sym, EnumToString(tf), (int)InpAppliedPrice, (int)InpWhichDerivative, + + InpPlotsUnifyYScale ? "on" : "off", + + InpDiffStep, InpNormalizePoints ? "on" : "off", InpSmoothPeriod); + + return false; + + } + + RemoveDerivativePlotsIndicatorsFromChart(); + + int sw = (int)ChartGetInteger(0, CHART_WINDOWS_TOTAL); + + ResetLastError(); + + const bool ok = ChartIndicatorAdd(0, sw, ind); + + const int errAfterAdd = GetLastError(); + + IndicatorRelease(ind); + + if(!ok) + + { + + g_derivativePlotsFailedToLoad = true; + + Print("DERIVATIVE_CALC: ChartIndicatorAdd failed err=", errAfterAdd, + + ". Expected file present: ", wantPath); + + return false; + + } + + g_derivativePlotsFailedToLoad = false; + + g_derivPlotsAttachDone = true; + + ChartRedraw(0); + + Print("DERIVATIVE_CALC: subwindow indicator attached (inputs synced from EA)."); + + if(InpDebugTrace) + + PrintFormat("DERIVATIVE_CALC dbg attach OK handle_was_valid ChartIndicatorAdd err=%d sym=%s tf=%s sw=%d", + + errAfterAdd, sym, EnumToString(tf), sw); + + return true; + +} + +void TryDemoTrade(const string sym, const ENUM_TIMEFRAMES tf, + + const double d1, const double d2, const double d3) + +{ + + if(!InpTradeEnabled || HasOurPosition(sym)) + + return; + + bool wantBuy = false; + + bool wantSell = false; + + switch(InpWhichDerivative) + + { + + case DERIVATIVE_ALL: + + case DERIVATIVE_LEVEL_1: + + wantBuy = (d1 > 0.0 && d2 > 0.0); + + wantSell = (d1 < 0.0 && d2 < 0.0); + + break; + + case DERIVATIVE_LEVEL_2: + + wantBuy = (d2 > 0.0); + + wantSell = (d2 < 0.0); + + break; + + default: + + wantBuy = (d3 > 0.0); + + wantSell = (d3 < 0.0); + + break; + + } + + if(!wantBuy && !wantSell) + + return; + + MqlTick tick; + + if(!SymbolInfoTick(sym, tick)) + + return; + + const double atrPts = AtrPoints(sym, tf); + + const double pt = SymbolInfoDouble(sym, SYMBOL_POINT); + + const double slPts = MathMax(atrPts * InpSlAtrMult, 10.0); + + const double tpPts = MathMax(atrPts * InpTpAtrMult, 10.0); + + double sl = 0.0, tp = 0.0; + + if(wantBuy) + + { + + sl = tick.ask - slPts * pt; + + tp = tick.ask + tpPts * pt; + + g_trade.Buy(InpLots, sym, tick.ask, sl, tp, "DERIVATIVE_CALC demo"); + + } + + else if(wantSell) + + { + + sl = tick.bid + slPts * pt; + + tp = tick.bid - tpPts * pt; + + g_trade.Sell(InpLots, sym, tick.bid, sl, tp, "DERIVATIVE_CALC demo"); + + } + +} + +int OnInit() + +{ + + g_derivPlotsAttachDone = false; + + g_lastCommentWallMs = 0; + + g_chartSymbol = InpSymbol; + + StringTrimLeft(g_chartSymbol); + + StringTrimRight(g_chartSymbol); + + if(StringLen(g_chartSymbol) == 0) + + g_chartSymbol = _Symbol; + + if(!SymbolSelect(g_chartSymbol, true)) + + { + + Print("DERIVATIVE_CALC EA: cannot select symbol ", g_chartSymbol); + + return INIT_FAILED; + + } + + g_trade.SetExpertMagicNumber((long)InpMagic); + + g_trade.SetDeviationInPoints(InpSlippagePoints); + + g_trade.SetTypeFillingBySymbol(g_chartSymbol); + + ENUM_TIMEFRAMES tf = InpSignalTF; + + if(tf == PERIOD_CURRENT) + + tf = (ENUM_TIMEFRAMES)Period(); + + Print("DERIVATIVE_CALC EA started on ", g_chartSymbol, " ", EnumToString(tf), + + ". This is an Expert Advisor — not the Accelerator indicator."); + + if(InpDebugTrace) + + PrintFormat("DERIVATIVE_CALC dbg chart_TF=%s signal_TF=%s normalize=%s h=%d sm=%d tester=%s visual=%s", + + EnumToString((ENUM_TIMEFRAMES)Period()), EnumToString(tf), + + InpNormalizePoints ? "on" : "off", InpDiffStep, InpSmoothPeriod, + + MQLInfoInteger(MQL_TESTER) ? "yes" : "no", + + MQLInfoInteger(MQL_VISUAL_MODE) ? "yes" : "no"); + + DeleteOurHelpObjects(); + + TryBuildHelpPanel(); + + // Do not call iCustom / ChartIndicatorAdd here — Strategy Tester treats failed indicator load in OnInit as a critical error. + + // Attachment runs on first OnTick instead (see g_pendingDerivativePlotsAttach). + + if(InpUseCanvasPlots) + + { + + RemoveDerivativePlotsIndicatorsFromChart(); + + EventSetMillisecondTimer(120); + + } + + else + + EventKillTimer(); + + if(InpAutoAttachDerivativePlots && !InpUseCanvasPlots) + + { + + RemoveDerivativePlotsIndicatorsFromChart(); + + const bool in_tester = (MQLInfoInteger(MQL_TESTER) != 0); + + const bool visual = (MQLInfoInteger(MQL_VISUAL_MODE) != 0); + + const bool skip_tester_attach = (in_tester && !visual && !InpAttachPlotsInTester); + + if(skip_tester_attach) + + { + + Print("DERIVATIVE_CALC: non-visual Strategy Tester - skipping DerivativePlots attach. ", + + "Use visual mode for subwindow plots, or set InpAttachPlotsInTester=true if DerivativePlots.ex5 is in MQL5\\Indicators\\."); + + } + + else + + { + + g_pendingDerivativePlotsAttach = true; + + Print("DERIVATIVE_CALC: DerivativePlots attach scheduled on first tick (OnInit cannot safely load custom indicators in tester)."); + + } + + } + + return INIT_SUCCEEDED; + +} + +void OnDeinit(const int reason) + +{ + + EventKillTimer(); + + if(g_deriv_canvas_created) + + { + + g_deriv_canvas.Destroy(); + + g_deriv_canvas_created = false; + + } + + ObjectDelete(0, DERIV_CANVAS_OBJ); + + g_derivPlotsAttachDone = false; + + DeleteOurHelpObjects(); + + Comment(""); + +} + +void OnTimer() + +{ + + if(!InpUseCanvasPlots) + + return; + + const uint now = GetTickCount(); + + if(InpCanvasRedrawMs > 0 && g_lastCanvasRedrawMs != 0 && + + (now - g_lastCanvasRedrawMs) < (uint)InpCanvasRedrawMs) + + return; + + g_lastCanvasRedrawMs = now; + + UpdateDerivativeCanvasStrip(); + +} + +void OnTick() + +{ + + ENUM_TIMEFRAMES tf = InpSignalTF; + + if(tf == PERIOD_CURRENT) + + tf = (ENUM_TIMEFRAMES)Period(); + + if(g_pendingDerivativePlotsAttach && !InpUseCanvasPlots) + + { + + g_pendingDerivativePlotsAttach = false; + + AttachDerivativePlotsIndicator(g_chartSymbol, tf); + + } + + const datetime barOpen = iTime(g_chartSymbol, tf, 0); + + if(barOpen == 0) + + return; + + if(barOpen == g_lastBarTime) + + return; + + g_lastBarTime = barOpen; + + double d1 = 0.0, d2 = 0.0, d3 = 0.0; + + if(!ComputeDerivatives(g_chartSymbol, tf, d1, d2, d3)) + + { + + if(InpDebugTrace) + + PrintFormat("DERIVATIVE_CALC dbg ComputeDerivatives FAILED sym=%s tf=%s bar=%s pt=%.12g", + + g_chartSymbol, EnumToString(tf), TimeToString(barOpen, TIME_DATE | TIME_MINUTES), + + SymbolInfoDouble(g_chartSymbol, SYMBOL_POINT)); + + if(InpShowComment) + + CommentThrottled("DERIVATIVE_CALC: not enough bars yet on " + g_chartSymbol + " " + EnumToString(tf) + + + DerivativePlotsMissingHint()); + + return; + + } + + if(InpDebugTrace) + + PrintFormat("DERIVATIVE_CALC dbg bar=%s sym=%s chart_TF=%s signal_TF=%s | d1=%.8g d2=%.8g d3=%.8g | pt=%.12g norm=%s h=%d", + + TimeToString(barOpen, TIME_DATE | TIME_MINUTES), g_chartSymbol, + + EnumToString((ENUM_TIMEFRAMES)Period()), EnumToString(tf), + + d1, d2, d3, SymbolInfoDouble(g_chartSymbol, SYMBOL_POINT), + + InpNormalizePoints ? "on" : "off", InpDiffStep); + + if(InpShowComment) + + { + + string c = "DERIVATIVE_CALC EA | " + g_chartSymbol + + + "\nChart TF: " + EnumToString((ENUM_TIMEFRAMES)Period()) + + + " Signal TF (inputs): " + EnumToString(tf) + + + "\nd1=" + DoubleToString(d1, 4) + " d2=" + DoubleToString(d2, 4) + " d3=" + DoubleToString(d3, 4) + + + "\n(InpWhichDerivative=" + IntegerToString((int)InpWhichDerivative) + + + " h=" + IntegerToString(InpDiffStep) + " sm=" + IntegerToString(InpSmoothPeriod) + ")" + + + (InpUseCanvasPlots + + ? "\nPlots: EA canvas strip (bottom of chart)." + + : ("\nPlots below: DerivativePlots indicator." + DerivativePlotsMissingHint())); + + CommentThrottled(c); + + } + + TryDemoTrade(g_chartSymbol, tf, d1, d2, d3); + +} + +//+------------------------------------------------------------------+ + diff --git a/lab/EAs/DerivativePlots.mq5 b/lab/EAs/DerivativePlots.mq5 new file mode 100644 index 0000000..5671e9f --- /dev/null +++ b/lab/EAs/DerivativePlots.mq5 @@ -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; +} + +//+------------------------------------------------------------------+ diff --git a/lab/EAs/TFXNZDUSD.mq5 b/lab/EAs/TFXNZDUSD.mq5 new file mode 100644 index 0000000..fb85078 --- /dev/null +++ b/lab/EAs/TFXNZDUSD.mq5 @@ -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 (H4–M15) 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 + +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()); +} + +//+------------------------------------------------------------------+ diff --git a/lab/EAs/TFXNZDUSD_Genetic_Optimization.set b/lab/EAs/TFXNZDUSD_Genetic_Optimization.set new file mode 100644 index 0000000..633c283 --- /dev/null +++ b/lab/EAs/TFXNZDUSD_Genetic_Optimization.set @@ -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 Min–Max 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 diff --git a/lab/EAs/TFXXAUUSDScalper.mq5 b/lab/EAs/TFXXAUUSDScalper.mq5 new file mode 100644 index 0000000..c029180 --- /dev/null +++ b/lab/EAs/TFXXAUUSDScalper.mq5 @@ -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 + +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 +} + +//+------------------------------------------------------------------+ diff --git a/lab/EAs/TFXXAUUSDScalper_Genetic_Optimization.set b/lab/EAs/TFXXAUUSDScalper_Genetic_Optimization.set new file mode 100644 index 0000000..a1dc8cf --- /dev/null +++ b/lab/EAs/TFXXAUUSDScalper_Genetic_Optimization.set @@ -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 Min–Max 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 diff --git a/lab/ematerminator/READY_EMACrossOverXAUUSD.mq5 b/lab/ematerminator/READY_EMACrossOverXAUUSD.mq5 new file mode 100644 index 0000000..3f3fdc2 --- /dev/null +++ b/lab/ematerminator/READY_EMACrossOverXAUUSD.mq5 @@ -0,0 +1,458 @@ +//+------------------------------------------------------------------+ +//| ScoringTrade.mq5 | +//| Generated by ChatGPT | +//| | +//+------------------------------------------------------------------+ +#property strict +#include + +// 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 +} diff --git a/lab/ematerminator/READY_EMACrossOverXAUUSD_Genetic_Optimization.set b/lab/ematerminator/READY_EMACrossOverXAUUSD_Genetic_Optimization.set new file mode 100644 index 0000000..07722d6 --- /dev/null +++ b/lab/ematerminator/READY_EMACrossOverXAUUSD_Genetic_Optimization.set @@ -0,0 +1,55 @@ +; READY_EMACrossOverXAUUSD.mq5 — Genetic optimization (sanitized ranges) +; Load: Strategy Tester → Inputs → Load +; Format: Name=Default||Min||Step||Max||Y/N +; +; Units (read before optimizing): +; slopeThreshold — |ΔEMA|×100 per chart bar; ~93 ≈ $0.93 EMA move (H1 EMA, checked each tick) +; distanceThreshold — |price−EMA| in price ($ for XAUUSD) +; cooldown* — minutes +; atrMultiplier — stop distance = ATR(14) × multiplier (price $) +; TrailingStop — trail in symbol POINTS (0.01 pt on XAU: 500≈$5). EA default 5≈$0.05 — set uses 500 for tests. +; reverseTP — close reversal basket when profit ≥ this (account currency) +; reverseLotSizeMultiplier — reversal volume = position volume × this (dangerous above ~5) +; score* — arbitrary units; keep threshold ~4–10× crossOverStep or ~8–15 ticks of slope step +; +; ENUM_TIMEFRAMES: H1=16385 — fixed; do not sweep enum range. + +; === fixed === +MagicNumber=42||42||1||42||N +minimumLotSize=0.01||0.01||0||0.01||N +emaTimeFrame=16385||16385||0||16385||N +UseTrailingStop=true||false||0||true||N +maxScore=7900||7900||0||7900||N +emaDecayStep=0||0||0||0||N +resetCrossoverTradeOnDistance=false||false||0||false||N +resetCrossoverNumber=0||0||0||0||N +maxTimeInPosition=9||9||0||9||N +max_drawdown=0.1||0.1||0||0.1||N + +; === EMA / slope (price-scaled) === +emaPeriod=64||40||4||88||Y +slopeThreshold=93||50||5||140||Y +distanceThreshold=28.5||12.0||2.0||45.0||Y + +; === score increments (keep proportional to scoreThreshold) === +scoreThreshold=5200||3500||250||7000||Y +crossOverStep=950||600||50||1400||Y +slopeThresholdStep=635||350||50||950||Y +emaDistanceStep=150||75||25||250||Y +delayClampAbsolute=1690||1000||100||2500||Y +decayMultiplier=0.08||0.03||0.01||0.15||Y + +; === timing === +cooldownMinutes=18||8||2||35||Y +tradeCooldownMinutes=24||12||3||48||Y +maxCrossoverTrades=4||2||1||6||Y + +; === stops / trail === +atrMultiplier=7.6||4.0||0.5||12.0||Y +TrailingStop=500||200||50||1000||Y + +; === reversal / hold (minutes & account $) === +tradeLengthThreshold=98||60||10||180||Y +secondaryPositionHoldTime=32||15||5||60||Y +reverseTP=32||15||5||80||Y +reverseLotSizeMultiplier=15||4||1||20||Y diff --git a/self-coding-agent/README.md b/self-coding-agent/README.md new file mode 100644 index 0000000..f244561 --- /dev/null +++ b/self-coding-agent/README.md @@ -0,0 +1,79 @@ +# Self-coding agent (MQL5 + MT5 + Ollama, long-running) + +This is a **local, long-running loop** that calls **Ollama** on your machine, lets the model **read/write allowed paths** in this repo (including MQL5 under `frontline/` and `lab/`), **fetch documentation** over HTTP, and optionally run the **Python MT5 backtest harness** in `backtesting/MT5/`. It keeps a **journal** and a small **evolution** memory so each iteration can build on the last. + +It does **not** embed inside MetaTrader as an EA. For **Strategy Tester** on `.mq5` files, MT5’s terminal still has to compile and run tests; this agent automates the **Python** side and file edits. MQL5 compile verification can be added later via MetaEditor CLI if you want strict compile checks. + +## What “indefinite” means here + +`main.py` runs until you press **Ctrl+C** (or the process is stopped by your supervisor). For true daemon operation, run it under **Windows Task Scheduler**, **NSSM**, **systemd**, or a container restart policy. + +Set `loop.max_iterations` to `0` in `config.yaml` for unlimited iterations (default in `config.example.yaml`). + +## Requirements + +- **Python 3.10+** +- **Ollama** running locally (`ollama serve`) with a model pulled (see `ollama list`; `config.example.yaml` defaults to `qwen2.5-coder:7b`). +- Optional: **MetaTrader 5** installed and logged in for `run_backtest` / `MetaTrader5` Python package (see `backtesting/MT5/README.md`) + +## Quick start + +```powershell +cd d:\profitable-expert-advisor\self-coding-agent +python -m venv .venv +.\.venv\Scripts\activate +pip install -r requirements.txt +copy config.example.yaml config.yaml +# Edit config.yaml: set ollama.model, mission, allowed_path_prefixes if needed +python main.py +``` + +### CLI overrides (good for smoke tests) + +```powershell +python main.py --max-iterations 2 --model qwen2.5-coder:7b --no-mt5-backtest --sleep-seconds 0 +``` + +### Automated smoke tests (no Ollama) + +```powershell +python -m unittest discover -s tests -p "test_*.py" -v +``` + +On first failure to connect to Ollama, the loop backs off and retries (see `loop.consecutive_error_limit`). + +## Configuration + +- **`config.yaml`**: optional; if missing, `config.example.yaml` is used as defaults. +- **`workspace_root`**: default `..` resolves to the **repository root** (parent of `self-coding-agent/`). +- **`allowed_path_prefixes`**: hard sandbox for `read_file` / `write_file` / `list_dir`. Tighten this in production. +- **`mt5_backtest`**: toggles subprocess calls to `backtesting/MT5/run_backtest.py`. +- **`cursor.open_in_cursor_after_write`**: if `true`, tries `cursor ` on each write (requires `cursor` on PATH). + +## Cursor integration + +- **This script is not the Cursor IDE.** It complements Cursor: you can leave it running while you work in Cursor on the same repo. +- **Programmatic Cursor agents** (outside this repo) use the Cursor TypeScript SDK; see the Cursor SDK skill in your environment if you want CI/agents that call Cursor Cloud APIs with credentials. +- **Practical hybrid workflow:** run this agent for breadth (many small iterations, local model cost = $0); use Cursor for focused refactors, reviews, and hard problems. + +## Self-evolve / self-improve (what is implemented) + +- **`state/journal.jsonl`**: one JSON record per iteration (reflection, actions, errors). +- **`state/evolution.json`**: stores recent backtest stdout/stderr tails when `run_backtest` runs, so later prompts include a short “what happened last time” hint. + +This is **deliberately minimal**: you can extend `agent/memory.py` to track numeric metrics, Pareto fronts, or mutation of parameters. + +## Safety notes + +- The model can only touch paths under **`allowed_path_prefixes`**. +- There is **no arbitrary shell** tool; only `run_backtest` and `run_python` with an allowlisted script path under the repo. +- **`fetch_url`** is HTTP(S) only; responses are size-capped. + +## Ollama API + +The client uses `POST /api/chat` with `stream: false`. Compatible with current Ollama HTTP API. + +## Troubleshooting + +- **`json.JSONDecodeError`**: the agent now prints a truncated copy of the model output to the console. Try a coder-tuned model, lower `temperature`, or raise `num_ctx` in `ollama.options`. +- **MT5 backtest fails**: run `python backtesting/MT5/test_setup.py` from repo root with MT5 open; see `backtesting/MT5/QUICKSTART.md`. On Windows, avoid Unicode symbols in console scripts (this repo’s `test_setup.py` uses ASCII markers like `[OK]`). diff --git a/self-coding-agent/__pycache__/main.cpython-312.pyc b/self-coding-agent/__pycache__/main.cpython-312.pyc new file mode 100644 index 0000000..25092de Binary files /dev/null and b/self-coding-agent/__pycache__/main.cpython-312.pyc differ diff --git a/self-coding-agent/agent/__init__.py b/self-coding-agent/agent/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/self-coding-agent/agent/__pycache__/__init__.cpython-312.pyc b/self-coding-agent/agent/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..08daaf7 Binary files /dev/null and b/self-coding-agent/agent/__pycache__/__init__.cpython-312.pyc differ diff --git a/self-coding-agent/agent/__pycache__/config.cpython-312.pyc b/self-coding-agent/agent/__pycache__/config.cpython-312.pyc new file mode 100644 index 0000000..4ab3e92 Binary files /dev/null and b/self-coding-agent/agent/__pycache__/config.cpython-312.pyc differ diff --git a/self-coding-agent/agent/__pycache__/loop.cpython-312.pyc b/self-coding-agent/agent/__pycache__/loop.cpython-312.pyc new file mode 100644 index 0000000..ac22562 Binary files /dev/null and b/self-coding-agent/agent/__pycache__/loop.cpython-312.pyc differ diff --git a/self-coding-agent/agent/__pycache__/memory.cpython-312.pyc b/self-coding-agent/agent/__pycache__/memory.cpython-312.pyc new file mode 100644 index 0000000..6abba61 Binary files /dev/null and b/self-coding-agent/agent/__pycache__/memory.cpython-312.pyc differ diff --git a/self-coding-agent/agent/__pycache__/ollama_client.cpython-312.pyc b/self-coding-agent/agent/__pycache__/ollama_client.cpython-312.pyc new file mode 100644 index 0000000..748735b Binary files /dev/null and b/self-coding-agent/agent/__pycache__/ollama_client.cpython-312.pyc differ diff --git a/self-coding-agent/agent/__pycache__/tools.cpython-312.pyc b/self-coding-agent/agent/__pycache__/tools.cpython-312.pyc new file mode 100644 index 0000000..33654ec Binary files /dev/null and b/self-coding-agent/agent/__pycache__/tools.cpython-312.pyc differ diff --git a/self-coding-agent/agent/config.py b/self-coding-agent/agent/config.py new file mode 100644 index 0000000..6cac834 --- /dev/null +++ b/self-coding-agent/agent/config.py @@ -0,0 +1,42 @@ +from __future__ import annotations + +import copy +from pathlib import Path +from typing import Any, Dict + +import yaml + +AGENT_DIR = Path(__file__).resolve().parent.parent + + +def _deep_merge(base: Dict[str, Any], override: Dict[str, Any]) -> Dict[str, Any]: + out = copy.deepcopy(base) + for k, v in override.items(): + if k in out and isinstance(out[k], dict) and isinstance(v, dict): + out[k] = _deep_merge(out[k], v) + else: + out[k] = copy.deepcopy(v) + return out + + +def default_config() -> Dict[str, Any]: + example = AGENT_DIR / "config.example.yaml" + if example.is_file(): + with example.open("r", encoding="utf-8") as f: + return yaml.safe_load(f) or {} + return {} + + +def load_config() -> Dict[str, Any]: + path = AGENT_DIR / "config.yaml" + base = default_config() + if not path.is_file(): + return base + with path.open("r", encoding="utf-8") as f: + user = yaml.safe_load(f) or {} + return _deep_merge(base, user) + + +def workspace_path(cfg: Dict[str, Any]) -> Path: + rel = cfg.get("workspace_root", "..") + return (AGENT_DIR / rel).resolve() diff --git a/self-coding-agent/agent/loop.py b/self-coding-agent/agent/loop.py new file mode 100644 index 0000000..c4185cf --- /dev/null +++ b/self-coding-agent/agent/loop.py @@ -0,0 +1,210 @@ +from __future__ import annotations + +import json +import time +import traceback +from typing import Any, Dict, List + +from .config import load_config, workspace_path +from .memory import append_journal, load_evolution, maybe_update_evolution, tail_journal +from .ollama_client import chat +from .tools import ToolExecutor, ToolError, parse_model_json + + +ACTION_SCHEMA = r""" +You must reply with ONLY a single raw JSON object (no markdown fences, no commentary) of this form: +{ + "reflection": "short reasoning", + "actions": [ + {"type": "list_dir", "path": "frontline/units"}, + {"type": "read_file", "path": "relative/path/from/repo/root.mq5"}, + {"type": "write_file", "path": "self-coding-agent/generated/example.txt", "content": "file contents"}, + {"type": "fetch_url", "url": "https://..."}, + {"type": "run_backtest", "strategy": "RSIReversalStrategy", "symbol": "XAUUSD", "start": "2023-01-01", "end": "2024-01-01", "timeframe": "H1"}, + {"type": "run_python", "script_relative": "backtesting/MT5/test_setup.py", "args": []} + ] +} + +Rules: +- Paths are relative to the repository root and must stay under allowed prefixes. +- Prefer reading before writing; keep edits minimal and compile-friendly for MQL5. +- Use fetch_url for MQL5 documentation pages when unsure about APIs. +- run_backtest uses the repo's Python MT5 harness (MetaTrader 5 terminal must be installed/running). +- If you only need to think, use an empty actions list. +""" + + +def build_system_message(cfg: Dict[str, Any]) -> str: + mission = str(cfg.get("mission") or "").strip() + prefixes = cfg.get("allowed_path_prefixes") or [] + return ( + mission + + "\n\nAllowed path prefixes (read/write/list):\n" + + "\n".join(f"- {p}" for p in prefixes) + + "\n\n" + + ACTION_SCHEMA + ) + + +def build_user_message( + iteration: int, + last_results: str, + journal_tail: str, + evolution_hint: str, +) -> str: + parts = [ + f"Iteration: {iteration}", + "Previous tool results (JSON):\n```json\n" + + last_results + + "\n```", + ] + if journal_tail.strip(): + parts.append("Recent journal (tail):\n" + journal_tail) + if evolution_hint.strip(): + parts.append("Evolution memory hint:\n" + evolution_hint) + parts.append( + "Plan the next improvements and output your JSON response. " + "If this is iteration 1 and there is no parse error yet, prefer list_dir/read_file only; " + "avoid run_backtest until you have read relevant code." + ) + return "\n\n".join(parts) + + +def run_loop( + *, + max_iterations: int | None = None, + model: str | None = None, + sleep_seconds: float | None = None, + mt5_backtest_enabled: bool | None = None, +) -> None: + cfg = load_config() + if mt5_backtest_enabled is not None: + cfg.setdefault("mt5_backtest", {})["enabled"] = bool(mt5_backtest_enabled) + ws = workspace_path(cfg) + ex = ToolExecutor(cfg, ws) + + ollama = cfg.get("ollama") or {} + base_url = str(ollama.get("base_url", "http://127.0.0.1:11434")) + model_name = str(model or ollama.get("model", "llama3.2")) + options = ollama.get("options") or {} + + loop_cfg = cfg.get("loop") or {} + max_iters = int(max_iterations if max_iterations is not None else loop_cfg.get("max_iterations", 0)) + sleep_s = float(sleep_seconds if sleep_seconds is not None else loop_cfg.get("sleep_seconds", 2.0)) + err_limit = int(loop_cfg.get("consecutive_error_limit", 15)) + + mem_cfg = cfg.get("memory") or {} + journal_max = int(mem_cfg.get("journal_max_lines", 80)) + + system = build_system_message(cfg) + + iteration = 0 + consecutive_errors = 0 + last_results_json = json.dumps({"info": "No previous tool results yet."}) + + while True: + iteration += 1 + if max_iters and iteration > max_iters: + print(f"Stopping: reached max_iterations={max_iters}", flush=True) + return + + ev = load_evolution(cfg) + ev_notes = ev.get("notes") or [] + evolution_hint = "" + if ev_notes: + evolution_hint = json.dumps(ev_notes[-3:], ensure_ascii=False) + + journal_tail = tail_journal(cfg, journal_max) + user = build_user_message(iteration, last_results_json, journal_tail, evolution_hint) + + messages: List[Dict[str, str]] = [ + {"role": "system", "content": system}, + {"role": "user", "content": user}, + ] + + try: + raw = chat(base_url, model_name, messages, options=options) + try: + plan = parse_model_json(raw) + except json.JSONDecodeError: + tail = raw if len(raw) <= 4000 else raw[:4000] + "\n...[truncated]..." + print("Model returned non-JSON; raw (truncated):\n" + tail + "\n---", flush=True) + raise + actions = plan.get("actions") or [] + if not isinstance(actions, list): + raise ValueError("actions must be a list") + + results: List[Dict[str, Any]] = [] + backtest_blob = "" + max_actions = 12 + for i, action in enumerate(actions[:max_actions]): + if not isinstance(action, dict): + results.append({"ok": False, "error": "action must be an object"}) + continue + try: + r = ex.execute(action) + results.append({"action": action, "result": r}) + if action.get("type") == "run_backtest": + stdout = str((r or {}).get("stdout") or "") + stderr = str((r or {}).get("stderr") or "") + backtest_blob = stdout + "\n" + stderr + except ToolError as e: + results.append({"action": action, "result": {"ok": False, "error": str(e)}}) + except Exception as e: + results.append( + {"action": action, "result": {"ok": False, "error": f"{type(e).__name__}: {e}"}} + ) + + last_results_json = json.dumps( + { + "reflection": plan.get("reflection"), + "parsed_ok": True, + "tool_results": results, + }, + ensure_ascii=False, + ) + + if backtest_blob.strip(): + maybe_update_evolution(cfg, iteration, backtest_blob) + + append_journal( + cfg, + { + "iteration": iteration, + "reflection": plan.get("reflection"), + "actions": actions[:max_actions], + "ok": True, + }, + ) + + consecutive_errors = 0 + print( + f"[iter {iteration}] ok reflection={str(plan.get('reflection', ''))[:160]!r} " + f"actions={len(actions[:max_actions])}", + flush=True, + ) + time.sleep(max(0.0, sleep_s)) + + except KeyboardInterrupt: + print("Interrupted by user; exiting.", flush=True) + return + except Exception as e: + consecutive_errors += 1 + err_text = f"{type(e).__name__}: {e}\n{traceback.format_exc()[-4000:]}" + print(err_text, flush=True) + append_journal( + cfg, + { + "iteration": iteration, + "ok": False, + "error": err_text, + }, + ) + last_results_json = json.dumps({"parse_or_run_error": err_text}, ensure_ascii=False) + backoff = min(300.0, float(2 ** min(consecutive_errors, 8))) + if consecutive_errors >= err_limit: + print( + f"Many consecutive errors ({consecutive_errors}); sleeping {backoff:.1f}s before retry.", + flush=True, + ) + time.sleep(backoff) diff --git a/self-coding-agent/agent/memory.py b/self-coding-agent/agent/memory.py new file mode 100644 index 0000000..401c568 --- /dev/null +++ b/self-coding-agent/agent/memory.py @@ -0,0 +1,83 @@ +from __future__ import annotations + +import json +from datetime import datetime, timezone +from pathlib import Path +from typing import Any, Dict, List + +from .config import AGENT_DIR + + +def _utc_now_iso() -> str: + return datetime.now(timezone.utc).replace(microsecond=0).isoformat() + + +def journal_path(cfg: Dict[str, Any]) -> Path: + return AGENT_DIR / "state" / "journal.jsonl" + + +def evolution_path(cfg: Dict[str, Any]) -> Path: + rel = (cfg.get("memory") or {}).get("evolution_path", "state/evolution.json") + return (AGENT_DIR / rel).resolve() + + +def append_journal(cfg: Dict[str, Any], record: Dict[str, Any]) -> None: + p = journal_path(cfg) + p.parent.mkdir(parents=True, exist_ok=True) + line = json.dumps(record, ensure_ascii=False) + "\n" + with p.open("a", encoding="utf-8") as f: + f.write(line) + + +def tail_journal(cfg: Dict[str, Any], max_lines: int) -> str: + p = journal_path(cfg) + if not p.is_file(): + return "" + lines: List[str] = [] + with p.open("r", encoding="utf-8") as f: + for line in f: + lines.append(line.rstrip("\n")) + tail = lines[-max_lines:] if max_lines > 0 else lines + return "\n".join(tail) + + +def load_evolution(cfg: Dict[str, Any]) -> Dict[str, Any]: + p = evolution_path(cfg) + if not p.is_file(): + return { + "version": 1, + "created": _utc_now_iso(), + "best": None, + "notes": [], + } + with p.open("r", encoding="utf-8") as f: + return json.load(f) + + +def save_evolution(cfg: Dict[str, Any], data: Dict[str, Any]) -> None: + p = evolution_path(cfg) + p.parent.mkdir(parents=True, exist_ok=True) + with p.open("w", encoding="utf-8") as f: + json.dump(data, f, indent=2, ensure_ascii=False) + + +def maybe_update_evolution( + cfg: Dict[str, Any], + iteration: int, + backtest_stdout: str, +) -> str: + """ + Heuristic: if stdout mentions profit / return, store snippet for self-improve prompts. + """ + ev = load_evolution(cfg) + snippet = backtest_stdout[-6000:] if backtest_stdout else "" + note = { + "t": _utc_now_iso(), + "iteration": iteration, + "stdout_tail": snippet[-2000:], + } + notes = ev.get("notes") or [] + notes.append(note) + ev["notes"] = notes[-200:] + save_evolution(cfg, ev) + return json.dumps(note, ensure_ascii=False) diff --git a/self-coding-agent/agent/ollama_client.py b/self-coding-agent/agent/ollama_client.py new file mode 100644 index 0000000..a23c4e9 --- /dev/null +++ b/self-coding-agent/agent/ollama_client.py @@ -0,0 +1,32 @@ +from __future__ import annotations + +import json +from typing import Any, Dict, List, Optional + +import httpx + + +def chat( + base_url: str, + model: str, + messages: List[Dict[str, str]], + options: Optional[Dict[str, Any]] = None, + timeout: float = 600.0, +) -> str: + url = base_url.rstrip("/") + "/api/chat" + payload: Dict[str, Any] = { + "model": model, + "messages": messages, + "stream": False, + } + if options: + payload["options"] = options + with httpx.Client(timeout=timeout) as client: + r = client.post(url, json=payload) + r.raise_for_status() + data = r.json() + msg = data.get("message") or {} + content = msg.get("content") + if not isinstance(content, str): + raise RuntimeError(f"Unexpected Ollama response: {json.dumps(data)[:800]}") + return content diff --git a/self-coding-agent/agent/tools.py b/self-coding-agent/agent/tools.py new file mode 100644 index 0000000..5ba4a83 --- /dev/null +++ b/self-coding-agent/agent/tools.py @@ -0,0 +1,201 @@ +from __future__ import annotations + +import json +import subprocess +import re +from pathlib import Path +from typing import Any, Dict +from urllib.parse import urlparse + +import httpx + +from .config import AGENT_DIR + + +class ToolError(Exception): + pass + + +def _norm_rel(p: str) -> str: + return p.replace("\\", "/").strip().lstrip("/") + + +class ToolExecutor: + def __init__(self, cfg: Dict[str, Any], workspace: Path): + self.cfg = cfg + self.workspace = workspace + prefixes = cfg.get("allowed_path_prefixes") or [] + self.prefixes = tuple(_norm_rel(x) for x in prefixes) + + def _resolve_under_workspace(self, rel: str) -> Path: + rel_n = _norm_rel(rel) + if rel_n.startswith("..") or "/../" in f"/{rel_n}/": + raise ToolError("Path traversal is not allowed") + path = (self.workspace / rel_n).resolve() + try: + path.relative_to(self.workspace) + except ValueError as e: + raise ToolError("Path escapes workspace") from e + ok = any( + rel_n == pref.rstrip("/") or rel_n.startswith(pref.rstrip("/") + "/") + for pref in self.prefixes + ) + if not ok: + raise ToolError(f"Path not allowed by allowed_path_prefixes: {rel_n}") + return path + + def execute(self, action: Dict[str, Any]) -> Dict[str, Any]: + t = action.get("type") + if t == "read_file": + return self._read_file(str(action.get("path", ""))) + if t == "write_file": + return self._write_file(str(action.get("path", "")), str(action.get("content", ""))) + if t == "list_dir": + return self._list_dir(str(action.get("path", ""))) + if t == "fetch_url": + return self._fetch_url(str(action.get("url", ""))) + if t == "run_backtest": + return self._run_backtest(action) + if t == "run_python": + return self._run_python(action) + raise ToolError(f"Unknown action type: {t!r}") + + def _read_file(self, rel: str) -> Dict[str, Any]: + path = self._resolve_under_workspace(rel) + if not path.is_file(): + return {"ok": False, "error": f"Not a file: {rel}"} + text = path.read_text(encoding="utf-8", errors="replace") + if len(text) > 120_000: + text = text[:120_000] + "\n\n...[truncated]..." + return {"ok": True, "path": rel, "content": text} + + def _write_file(self, rel: str, content: str) -> Dict[str, Any]: + path = self._resolve_under_workspace(rel) + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(content, encoding="utf-8") + cursor_cfg = (self.cfg.get("cursor") or {}) + if cursor_cfg.get("open_in_cursor_after_write"): + try: + subprocess.Popen( + ["cursor", str(path)], + cwd=str(self.workspace), + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + except OSError: + pass + return {"ok": True, "path": rel, "bytes": len(content.encode("utf-8"))} + + def _list_dir(self, rel: str) -> Dict[str, Any]: + path = self._resolve_under_workspace(rel) + if not path.is_dir(): + return {"ok": False, "error": f"Not a directory: {rel}"} + names = sorted(p.name for p in path.iterdir()) + return {"ok": True, "path": rel, "entries": names[:500]} + + def _fetch_url(self, url: str) -> Dict[str, Any]: + web = self.cfg.get("web") or {} + timeout = float(web.get("fetch_timeout_seconds", 25)) + max_bytes = int(web.get("max_response_bytes", 400_000)) + u = urlparse(url) + if u.scheme not in ("http", "https") or not u.netloc: + raise ToolError("Only http(s) URLs with a host are allowed") + with httpx.Client(timeout=timeout, follow_redirects=True) as client: + r = client.get(url, headers={"User-Agent": "self-coding-agent/1.0"}) + r.raise_for_status() + body = r.content[:max_bytes] + ctype = r.headers.get("content-type", "") + text = body.decode("utf-8", errors="replace") + if len(text) > 80_000: + text = text[:80_000] + "\n\n...[truncated]..." + return {"ok": True, "url": url, "status": r.status_code, "content_type": ctype, "text": text} + + def _run_backtest(self, action: Dict[str, Any]) -> Dict[str, Any]: + mt5cfg = self.cfg.get("mt5_backtest") or {} + if not mt5cfg.get("enabled", True): + return {"ok": False, "skipped": True, "reason": "mt5_backtest.enabled is false"} + py = str(mt5cfg.get("python_executable", "python")) + script_rel = str(mt5cfg.get("script_relative", "backtesting/MT5/run_backtest.py")) + script = (self.workspace / _norm_rel(script_rel)).resolve() + try: + script.relative_to(self.workspace) + except ValueError as e: + raise ToolError("Backtest script outside workspace") from e + if not script.is_file(): + return {"ok": False, "error": f"Missing script: {script}"} + + strategy = str(action.get("strategy") or mt5cfg.get("default_strategy", "RSIReversalStrategy")) + symbol = str(action.get("symbol") or mt5cfg.get("default_symbol", "XAUUSD")) + start = str(action.get("start") or mt5cfg.get("default_start", "2023-01-01")) + end = str(action.get("end") or mt5cfg.get("default_end", "2024-01-01")) + timeframe = str(action.get("timeframe") or "H1") + + cmd = [ + py, + str(script), + "--strategy", + strategy, + "--symbol", + symbol, + "--start", + start, + "--end", + end, + "--timeframe", + timeframe, + ] + proc = subprocess.run( + cmd, + cwd=str(self.workspace), + capture_output=True, + text=True, + encoding="utf-8", + errors="replace", + ) + out = (proc.stdout or "") + ("\n" + proc.stderr if proc.stderr else "") + return { + "ok": proc.returncode == 0, + "returncode": proc.returncode, + "stdout": proc.stdout[-20000:] if proc.stdout else "", + "stderr": proc.stderr[-20000:] if proc.stderr else "", + } + + def _run_python(self, action: Dict[str, Any]) -> Dict[str, Any]: + rel = _norm_rel(str(action.get("script_relative", ""))) + if not rel.endswith(".py"): + raise ToolError("run_python only supports .py scripts") + script = self._resolve_under_workspace(rel) + if not script.is_file(): + return {"ok": False, "error": f"Missing script: {rel}"} + args = action.get("args") or [] + if not isinstance(args, list) or not all(isinstance(a, str) for a in args): + raise ToolError("args must be a list of strings") + py = str((self.cfg.get("mt5_backtest") or {}).get("python_executable", "python")) + cmd = [py, str(script), *args] + proc = subprocess.run( + cmd, + cwd=str(self.workspace), + capture_output=True, + text=True, + encoding="utf-8", + errors="replace", + ) + return { + "ok": proc.returncode == 0, + "returncode": proc.returncode, + "stdout": (proc.stdout or "")[-20000:], + "stderr": (proc.stderr or "")[-20000:], + } + + +def parse_model_json(text: str) -> Dict[str, Any]: + s = text.strip().lstrip("\ufeff") + fence = re.search(r"```(?:json)?\s*([\s\S]*?)\s*```", s, re.IGNORECASE) + if fence: + s = fence.group(1).strip() + if not s.lstrip().startswith("{"): + start = s.find("{") + end = s.rfind("}") + if start != -1 and end != -1 and end > start: + s = s[start : end + 1] + return json.loads(s) diff --git a/self-coding-agent/config.example.yaml b/self-coding-agent/config.example.yaml new file mode 100644 index 0000000..13c38ad --- /dev/null +++ b/self-coding-agent/config.example.yaml @@ -0,0 +1,51 @@ +# Copy to config.yaml and adjust. config.yaml is loaded if present. + +ollama: + base_url: "http://127.0.0.1:11434" + # Use a model you have pulled locally (`ollama list`). Coder-tuned models follow JSON better. + model: "qwen2.5-coder:7b" + # Options passed to Ollama /api/chat + options: + temperature: 0.35 + num_ctx: 8192 + +workspace_root: ".." # relative to self-coding-agent/ — repo root + +# Only paths under workspace_root matching these prefixes are readable/writable. +allowed_path_prefixes: + - "frontline/" + - "lab/" + - "self-coding-agent/generated/" + - "backtesting/MT5/" + +loop: + max_iterations: 0 # 0 = run forever until SIGINT/SIGTERM + sleep_seconds: 2.0 # pause between iterations + consecutive_error_limit: 15 # then exponential backoff (cap 300s) + +memory: + journal_max_lines: 80 # tail of journal.jsonl injected into prompts + evolution_path: "state/evolution.json" + +mt5_backtest: + enabled: true + python_executable: "python" + script_relative: "backtesting/MT5/run_backtest.py" + default_strategy: "RSIReversalStrategy" + default_symbol: "XAUUSD" + default_start: "2023-01-01" + default_end: "2024-01-01" + +web: + fetch_timeout_seconds: 25 + max_response_bytes: 400000 + +cursor: + # Optional: if `cursor` is on PATH, open generated files after writes (best-effort). + open_in_cursor_after_write: false + +mission: | + You are an autonomous coding agent for this trading/research repo. + Improve MQL5 Expert Advisors under frontline/units/ and lab/EAs/, or Python strategies + under backtesting/MT5/. Use actions to read files, write files, fetch docs from URLs, + and run backtests. Prefer small, testable edits. Output valid JSON only. diff --git a/self-coding-agent/generated/README.txt b/self-coding-agent/generated/README.txt new file mode 100644 index 0000000..c2816f8 --- /dev/null +++ b/self-coding-agent/generated/README.txt @@ -0,0 +1,2 @@ +This directory is writable by the self-coding agent (see allowed_path_prefixes in config). +Place generated snippets, notes, or experimental MQL5 here before promoting them into frontline/. diff --git a/self-coding-agent/main.py b/self-coding-agent/main.py new file mode 100644 index 0000000..887461c --- /dev/null +++ b/self-coding-agent/main.py @@ -0,0 +1,61 @@ +from __future__ import annotations + +import argparse +import sys +from pathlib import Path + +_ROOT = Path(__file__).resolve().parent +if str(_ROOT) not in sys.path: + sys.path.insert(0, str(_ROOT)) + +from agent.loop import run_loop + + +def _parse_args() -> argparse.Namespace: + p = argparse.ArgumentParser(description="Self-coding agent (Ollama + sandboxed tools)") + p.add_argument( + "--max-iterations", + type=int, + default=None, + help="Stop after N iterations (overrides config). Default: from config, 0 = infinite.", + ) + p.add_argument("--model", type=str, default=None, help="Ollama model name (overrides config).") + p.add_argument( + "--sleep-seconds", + type=float, + default=None, + help="Pause after each successful iteration (overrides config).", + ) + p.add_argument( + "--no-mt5-backtest", + action="store_true", + help="Disable subprocess MT5 Python backtests for this run.", + ) + p.add_argument( + "--mt5-backtest", + action="store_true", + help="Force-enable MT5 Python backtests for this run.", + ) + return p.parse_args() + + +def main() -> None: + args = _parse_args() + mt5: bool | None = None + if args.no_mt5_backtest and args.mt5_backtest: + raise SystemExit("Use only one of --no-mt5-backtest / --mt5-backtest") + if args.no_mt5_backtest: + mt5 = False + elif args.mt5_backtest: + mt5 = True + + run_loop( + max_iterations=args.max_iterations, + model=args.model, + sleep_seconds=args.sleep_seconds, + mt5_backtest_enabled=mt5, + ) + + +if __name__ == "__main__": + main() diff --git a/self-coding-agent/requirements.txt b/self-coding-agent/requirements.txt new file mode 100644 index 0000000..2c8ef07 --- /dev/null +++ b/self-coding-agent/requirements.txt @@ -0,0 +1,2 @@ +httpx>=0.27.0 +PyYAML>=6.0.1 diff --git a/self-coding-agent/state/.gitignore b/self-coding-agent/state/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/self-coding-agent/state/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/self-coding-agent/tests/__pycache__/test_smoke.cpython-312.pyc b/self-coding-agent/tests/__pycache__/test_smoke.cpython-312.pyc new file mode 100644 index 0000000..35dc464 Binary files /dev/null and b/self-coding-agent/tests/__pycache__/test_smoke.cpython-312.pyc differ diff --git a/self-coding-agent/tests/test_smoke.py b/self-coding-agent/tests/test_smoke.py new file mode 100644 index 0000000..9606aa2 --- /dev/null +++ b/self-coding-agent/tests/test_smoke.py @@ -0,0 +1,56 @@ +"""Smoke tests (no Ollama required). Run: python -m unittest discover -s tests -p 'test_*.py' -v""" + +from __future__ import annotations + +import sys +import unittest +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +if str(ROOT) not in sys.path: + sys.path.insert(0, str(ROOT)) + +from agent.config import load_config, workspace_path +from agent.tools import ToolExecutor, parse_model_json + + +class TestParseModelJson(unittest.TestCase): + def test_fence(self): + raw = """Here you go: +```json +{"reflection": "x", "actions": []} +``` +""" + d = parse_model_json(raw) + self.assertEqual(d["reflection"], "x") + self.assertEqual(d["actions"], []) + + def test_prose_then_braces(self): + raw = 'Thought: ok\n{"reflection": "r", "actions": [{"type": "list_dir", "path": "frontline/units"}]} trailing' + d = parse_model_json(raw) + self.assertEqual(d["reflection"], "r") + self.assertEqual(len(d["actions"]), 1) + + +class TestToolExecutor(unittest.TestCase): + def test_list_dir(self): + cfg = load_config() + ws = workspace_path(cfg) + ex = ToolExecutor(cfg, ws) + r = ex.execute({"type": "list_dir", "path": "frontline/units"}) + self.assertTrue(r.get("ok")) + self.assertIn("entries", r) + self.assertIsInstance(r["entries"], list) + + def test_disallowed_path(self): + cfg = load_config() + ws = workspace_path(cfg) + ex = ToolExecutor(cfg, ws) + from agent.tools import ToolError + + with self.assertRaises(ToolError): + ex.execute({"type": "read_file", "path": "README.md"}) + + +if __name__ == "__main__": + unittest.main()