Update
This commit is contained in:
@@ -1,327 +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.00"
|
||||
|
||||
#include <Trade\Trade.mqh>
|
||||
#include "../_united/MagicNumberHelpers.mqh"
|
||||
|
||||
//--- Input parameters
|
||||
input ENUM_TIMEFRAMES TimeFrame = PERIOD_H3; // 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 = 19; // RSI Overbought Level
|
||||
input double RSI_Oversold = 50; // RSI Oversold Level
|
||||
input double RSI_Target_Buy = 71; // RSI Target for Buy Exit
|
||||
input double RSI_Target_Sell = 70; // 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 = 12345; // Magic Number
|
||||
input int Slippage = 3; // Slippage in points
|
||||
|
||||
//--- Global variables
|
||||
CTrade trade;
|
||||
int rsi_handle;
|
||||
double rsi_buffer[];
|
||||
double rsi_prev, rsi_current, rsi_two_bars_ago;
|
||||
bool position_open = false;
|
||||
int position_ticket = 0;
|
||||
ENUM_POSITION_TYPE current_position_type = POSITION_TYPE_BUY;
|
||||
datetime last_bar_time = 0;
|
||||
bool rsi_against_position = false;
|
||||
int bars_against_count = 0;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Expert initialization function |
|
||||
//+------------------------------------------------------------------+
|
||||
int OnInit()
|
||||
{
|
||||
// Initialize RSI indicator
|
||||
rsi_handle = iRSI(_Symbol, TimeFrame, RSI_Period, RSI_Applied_Price);
|
||||
if(rsi_handle == INVALID_HANDLE)
|
||||
{
|
||||
return(INIT_FAILED);
|
||||
}
|
||||
|
||||
// Initialize trade object
|
||||
trade.SetExpertMagicNumber(MagicNumber);
|
||||
trade.SetDeviationInPoints(Slippage);
|
||||
trade.SetTypeFilling(ORDER_FILLING_FOK);
|
||||
|
||||
// Allocate arrays
|
||||
ArraySetAsSeries(rsi_buffer, true);
|
||||
|
||||
return(INIT_SUCCEEDED);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Expert deinitialization function |
|
||||
//+------------------------------------------------------------------+
|
||||
void OnDeinit(const int reason)
|
||||
{
|
||||
if(rsi_handle != INVALID_HANDLE)
|
||||
IndicatorRelease(rsi_handle);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Expert tick function |
|
||||
//+------------------------------------------------------------------+
|
||||
void OnTick()
|
||||
{
|
||||
// Check if we have enough bars
|
||||
if(Bars(_Symbol, TimeFrame) < RSI_Period + 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if this is a new bar
|
||||
datetime current_bar_time = iTime(_Symbol, TimeFrame, 0);
|
||||
if(current_bar_time == last_bar_time)
|
||||
{
|
||||
return; // Still the same bar, don't process
|
||||
}
|
||||
|
||||
last_bar_time = current_bar_time;
|
||||
|
||||
// Update RSI values
|
||||
if(!UpdateRSI())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for existing position
|
||||
CheckExistingPosition();
|
||||
|
||||
// Check for new entry signals - only if no position exists for THIS EA (magic number) on THIS symbol
|
||||
if(!position_open && !PositionExistsByMagic(_Symbol, MagicNumber))
|
||||
{
|
||||
CheckEntrySignals();
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Update RSI values |
|
||||
//+------------------------------------------------------------------+
|
||||
bool UpdateRSI()
|
||||
{
|
||||
if(CopyBuffer(rsi_handle, 0, 0, 3, rsi_buffer) < 3)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
rsi_current = rsi_buffer[0]; // Current bar
|
||||
rsi_prev = rsi_buffer[1]; // Previous bar
|
||||
rsi_two_bars_ago = rsi_buffer[2]; // Two bars ago
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check existing position for exit conditions |
|
||||
//+------------------------------------------------------------------+
|
||||
void CheckExistingPosition()
|
||||
{
|
||||
if(!position_open)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if position still exists with correct magic number AND symbol for THIS EA
|
||||
if(!PositionSelectByTicketSymbolAndMagic(position_ticket, _Symbol, MagicNumber))
|
||||
{
|
||||
position_open = false;
|
||||
position_ticket = 0;
|
||||
rsi_against_position = false;
|
||||
bars_against_count = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Exit conditions based on RSI target
|
||||
if(current_position_type == POSITION_TYPE_BUY)
|
||||
{
|
||||
// Check if RSI is against the position (below oversold)
|
||||
if(rsi_current < RSI_Oversold)
|
||||
{
|
||||
if(!rsi_against_position)
|
||||
{
|
||||
rsi_against_position = true;
|
||||
bars_against_count = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
bars_against_count++;
|
||||
}
|
||||
|
||||
// Close position if RSI has been against for Y bars
|
||||
if(bars_against_count >= BarsToWait)
|
||||
{
|
||||
ClosePosition();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// RSI is no longer against the position, reset counter
|
||||
if(rsi_against_position)
|
||||
{
|
||||
rsi_against_position = false;
|
||||
bars_against_count = 0;
|
||||
}
|
||||
|
||||
// Exit long position when RSI reaches buy target
|
||||
if(rsi_current >= RSI_Target_Buy)
|
||||
{
|
||||
ClosePosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(current_position_type == POSITION_TYPE_SELL)
|
||||
{
|
||||
// Check if RSI is against the position (above overbought)
|
||||
if(rsi_current > RSI_Overbought)
|
||||
{
|
||||
if(!rsi_against_position)
|
||||
{
|
||||
rsi_against_position = true;
|
||||
bars_against_count = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
bars_against_count++;
|
||||
}
|
||||
|
||||
// Close position if RSI has been against for Y bars
|
||||
if(bars_against_count >= BarsToWait)
|
||||
{
|
||||
ClosePosition();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// RSI is no longer against the position, reset counter
|
||||
if(rsi_against_position)
|
||||
{
|
||||
rsi_against_position = false;
|
||||
bars_against_count = 0;
|
||||
}
|
||||
|
||||
// Exit short position when RSI reaches sell target
|
||||
if(rsi_current <= RSI_Target_Sell)
|
||||
{
|
||||
ClosePosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check for entry signals |
|
||||
//+------------------------------------------------------------------+
|
||||
void CheckEntrySignals()
|
||||
{
|
||||
// Buy signal: RSI crosses from oversold to above oversold (checking the actual crossover)
|
||||
if(rsi_two_bars_ago <= RSI_Oversold && rsi_prev > RSI_Oversold)
|
||||
{
|
||||
OpenBuyPosition();
|
||||
}
|
||||
|
||||
// Sell signal: RSI crosses from overbought to below overbought (checking the actual crossover)
|
||||
if(rsi_two_bars_ago >= RSI_Overbought && rsi_prev < RSI_Overbought)
|
||||
{
|
||||
OpenSellPosition();
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Open buy position |
|
||||
//+------------------------------------------------------------------+
|
||||
void OpenBuyPosition()
|
||||
{
|
||||
// Verify no position exists for THIS EA (magic number) on THIS symbol before opening
|
||||
if(PositionExistsByMagic(_Symbol, MagicNumber))
|
||||
{
|
||||
return; // Position already exists for this EA
|
||||
}
|
||||
|
||||
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
||||
|
||||
if(trade.Buy(LotSize, _Symbol, ask, 0, 0, "RSI Scalping Buy"))
|
||||
{
|
||||
ulong new_ticket = trade.ResultOrder();
|
||||
if(new_ticket > 0)
|
||||
{
|
||||
// Verify position was opened for THIS EA (magic number) on THIS symbol
|
||||
if(PositionSelectByTicketSymbolAndMagic(new_ticket, _Symbol, MagicNumber))
|
||||
{
|
||||
position_ticket = new_ticket;
|
||||
position_open = true;
|
||||
current_position_type = POSITION_TYPE_BUY;
|
||||
}
|
||||
else
|
||||
{
|
||||
Print("Error: Position opened but doesn't match EA magic number or symbol");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Open sell position |
|
||||
//+------------------------------------------------------------------+
|
||||
void OpenSellPosition()
|
||||
{
|
||||
// Verify no position exists for THIS EA (magic number) on THIS symbol before opening
|
||||
if(PositionExistsByMagic(_Symbol, MagicNumber))
|
||||
{
|
||||
return; // Position already exists for this EA
|
||||
}
|
||||
|
||||
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
||||
|
||||
if(trade.Sell(LotSize, _Symbol, bid, 0, 0, "RSI Scalping Sell"))
|
||||
{
|
||||
ulong new_ticket = trade.ResultOrder();
|
||||
if(new_ticket > 0)
|
||||
{
|
||||
// Verify position was opened for THIS EA (magic number) on THIS symbol
|
||||
if(PositionSelectByTicketSymbolAndMagic(new_ticket, _Symbol, MagicNumber))
|
||||
{
|
||||
position_ticket = new_ticket;
|
||||
position_open = true;
|
||||
current_position_type = POSITION_TYPE_SELL;
|
||||
}
|
||||
else
|
||||
{
|
||||
Print("Error: Position opened but doesn't match EA magic number or symbol");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Close current position |
|
||||
//+------------------------------------------------------------------+
|
||||
void ClosePosition()
|
||||
{
|
||||
// Close position using helper that verifies symbol AND magic number for THIS EA
|
||||
if(ClosePositionByMagic(trade, _Symbol, MagicNumber))
|
||||
{
|
||||
position_open = false;
|
||||
position_ticket = 0;
|
||||
rsi_against_position = false;
|
||||
bars_against_count = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Position doesn't exist or wrong magic number - reset tracking
|
||||
position_open = false;
|
||||
position_ticket = 0;
|
||||
rsi_against_position = false;
|
||||
bars_against_count = 0;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 8.7 KiB |
@@ -0,0 +1,508 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| RSI_SecretSauce_XAUUSD.mq5 |
|
||||
//| Copyright 2025, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2025, MetaQuotes Ltd."
|
||||
#property link "https://www.mql5.com"
|
||||
#property version "1.01"
|
||||
#property description "RSI Secret Sauce Strategy: Wait for RSI to leave 70/30 zone, then enter when it comes back in"
|
||||
#property description "Based on momentum flip concept - not traditional overbought/oversold"
|
||||
|
||||
#include <Trade\Trade.mqh>
|
||||
#include <Trade\PositionInfo.mqh>
|
||||
|
||||
//--- Input Parameters
|
||||
input group "=== Trading Settings ==="
|
||||
input string InpSymbol = "XAUUSD"; // Trading Symbol (set was tuned on BTCUSD)
|
||||
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
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -259,7 +259,7 @@ bool InitRSIReversalAsian(RSIReversalAsianData& data, string symbol,
|
||||
double rsi[];
|
||||
ArraySetAsSeries(rsi, true);
|
||||
|
||||
int retryCount = 0;
|
||||
retryCount = 0;
|
||||
bool rsiInitialized = false;
|
||||
|
||||
while(retryCount < 10 && !rsiInitialized)
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| MagicNumberHelpers.mqh |
|
||||
//| Copyright 2025, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2025, MetaQuotes Ltd."
|
||||
#property link "https://www.mql5.com"
|
||||
#property version "1.00"
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Select position by symbol and magic number |
|
||||
//+------------------------------------------------------------------+
|
||||
bool PositionSelectByMagic(string symbol, ulong magic_number)
|
||||
{
|
||||
// First try to find position by symbol
|
||||
if(!PositionSelect(symbol))
|
||||
return false;
|
||||
|
||||
// Check if the selected position has the correct magic number
|
||||
if(PositionGetInteger(POSITION_MAGIC) != magic_number)
|
||||
{
|
||||
// Position exists but wrong magic number, search all positions
|
||||
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
||||
{
|
||||
if(PositionGetTicket(i) > 0)
|
||||
{
|
||||
if(PositionGetString(POSITION_SYMBOL) == symbol &&
|
||||
PositionGetInteger(POSITION_MAGIC) == magic_number)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Select position by ticket and verify magic number and symbol |
|
||||
//+------------------------------------------------------------------+
|
||||
bool PositionSelectByTicketAndMagic(ulong ticket, ulong magic_number)
|
||||
{
|
||||
if(!PositionSelectByTicket(ticket))
|
||||
return false;
|
||||
|
||||
return (PositionGetInteger(POSITION_MAGIC) == magic_number);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Select position by ticket and verify symbol, magic number |
|
||||
//+------------------------------------------------------------------+
|
||||
bool PositionSelectByTicketSymbolAndMagic(ulong ticket, string symbol, ulong magic_number)
|
||||
{
|
||||
if(!PositionSelectByTicket(ticket))
|
||||
return false;
|
||||
|
||||
return (PositionGetString(POSITION_SYMBOL) == symbol &&
|
||||
PositionGetInteger(POSITION_MAGIC) == magic_number);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check if position exists with correct magic number |
|
||||
//+------------------------------------------------------------------+
|
||||
bool PositionExistsByMagic(string symbol, ulong magic_number)
|
||||
{
|
||||
return PositionSelectByMagic(symbol, magic_number);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get position ticket by symbol and magic number |
|
||||
//+------------------------------------------------------------------+
|
||||
ulong GetPositionTicketByMagic(string symbol, ulong magic_number)
|
||||
{
|
||||
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
||||
{
|
||||
ulong ticket = PositionGetTicket(i);
|
||||
if(ticket > 0)
|
||||
{
|
||||
if(PositionGetString(POSITION_SYMBOL) == symbol &&
|
||||
PositionGetInteger(POSITION_MAGIC) == magic_number)
|
||||
{
|
||||
return ticket;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Close position by symbol and magic number |
|
||||
//+------------------------------------------------------------------+
|
||||
bool ClosePositionByMagic(CTrade &trade_obj, string symbol, ulong magic_number)
|
||||
{
|
||||
ulong ticket = GetPositionTicketByMagic(symbol, magic_number);
|
||||
if(ticket == 0)
|
||||
return false;
|
||||
|
||||
return trade_obj.PositionClose(ticket);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Modify position by symbol and magic number |
|
||||
//+------------------------------------------------------------------+
|
||||
bool ModifyPositionByMagic(CTrade &trade_obj, string symbol, ulong magic_number,
|
||||
double sl, double tp)
|
||||
{
|
||||
ulong ticket = GetPositionTicketByMagic(symbol, magic_number);
|
||||
if(ticket == 0)
|
||||
return false;
|
||||
|
||||
return trade_obj.PositionModify(ticket, sl, tp);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get position profit by symbol and magic number |
|
||||
//+------------------------------------------------------------------+
|
||||
double GetPositionProfitByMagic(string symbol, ulong magic_number)
|
||||
{
|
||||
if(!PositionSelectByMagic(symbol, magic_number))
|
||||
return 0.0;
|
||||
|
||||
return PositionGetDouble(POSITION_PROFIT);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get position type by symbol and magic number |
|
||||
//+------------------------------------------------------------------+
|
||||
ENUM_POSITION_TYPE GetPositionTypeByMagic(string symbol, ulong magic_number)
|
||||
{
|
||||
if(!PositionSelectByMagic(symbol, magic_number))
|
||||
return WRONG_VALUE;
|
||||
|
||||
return (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Count positions by symbol and magic number |
|
||||
//+------------------------------------------------------------------+
|
||||
int CountPositionsByMagic(string symbol, ulong magic_number)
|
||||
{
|
||||
int count = 0;
|
||||
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
||||
{
|
||||
ulong ticket = PositionGetTicket(i);
|
||||
if(ticket > 0)
|
||||
{
|
||||
if(PositionGetString(POSITION_SYMBOL) == symbol &&
|
||||
PositionGetInteger(POSITION_MAGIC) == magic_number)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,75 @@
|
||||
# Pepperstone US - Symbol Setup Guide
|
||||
|
||||
## Finding Correct Symbol Names in MetaTrader 5
|
||||
|
||||
### Step-by-Step Instructions:
|
||||
|
||||
1. **Open Market Watch Window**
|
||||
- Press `Ctrl+M` or go to `View > Market Watch`
|
||||
|
||||
2. **Show All Symbols**
|
||||
- Right-click in the Market Watch window
|
||||
- Select `Show All` or `Symbols`
|
||||
- This shows all available symbols from your broker
|
||||
|
||||
3. **Search for Your Symbols**
|
||||
- Use the search box in the Market Watch window
|
||||
- Search for: "AAPL", "MSFT", "NVDA", "TSLA", "BTCUSD", "XAUUSD"
|
||||
|
||||
4. **Note the Exact Symbol Name**
|
||||
- The symbol name shown in Market Watch is what you need to use
|
||||
- Common formats for Pepperstone US:
|
||||
- Stocks: `AAPL.US`, `MSFT.US`, `NVDA.US`, `TSLA.US`
|
||||
- Or: `NASDAQ:AAPL`, `NASDAQ:MSFT`, etc.
|
||||
- Or: Just `AAPL`, `MSFT`, etc. (if available)
|
||||
|
||||
5. **Add to Market Watch**
|
||||
- Double-click the symbol to add it to your Market Watch
|
||||
- Or right-click and select `Show`
|
||||
|
||||
6. **Update EA Inputs**
|
||||
- Open the EA inputs in MetaTrader 5
|
||||
- Update each symbol parameter with the exact name from Market Watch
|
||||
|
||||
## Common Pepperstone US Symbol Formats
|
||||
|
||||
### US Stocks:
|
||||
- **Apple**: `AAPL.US` or `NASDAQ:AAPL` or `AAPL`
|
||||
- **Microsoft**: `MSFT.US` or `NASDAQ:MSFT` or `MSFT`
|
||||
- **NVIDIA**: `NVDA.US` or `NASDAQ:NVDA` or `NVDA`
|
||||
- **Tesla**: `TSLA.US` or `NASDAQ:TSLA` or `TSLA`
|
||||
|
||||
### Cryptocurrencies:
|
||||
- **Bitcoin**: `BTCUSD` or `BTC/USD` or `BTCUSD.c`
|
||||
|
||||
### Precious Metals:
|
||||
- **Gold**: `XAUUSD` or `GOLD` or `XAU/USD`
|
||||
|
||||
## Important Notes:
|
||||
|
||||
1. **Symbol Names are Case-Sensitive**: Use exact capitalization
|
||||
2. **Add Symbols to Market Watch**: Symbols must be in Market Watch for the EA to access them
|
||||
3. **Check Trading Hours**: US stocks trade during US market hours (9:30 AM - 4:00 PM ET)
|
||||
4. **CFD vs Stock**: Pepperstone offers CFDs on stocks, not actual stocks
|
||||
5. **Spread**: Check the spread for each symbol - some may have wider spreads
|
||||
|
||||
## Troubleshooting:
|
||||
|
||||
### If Symbol Not Found:
|
||||
1. Check if you're connected to Pepperstone US server
|
||||
2. Verify your account type supports the symbol
|
||||
3. Contact Pepperstone support for symbol availability
|
||||
4. Check if symbol requires special account permissions
|
||||
|
||||
### If EA Shows "Symbol Not Available":
|
||||
1. Make sure symbol is added to Market Watch
|
||||
2. Verify symbol name matches exactly (including dots, colons, etc.)
|
||||
3. Check broker connection status
|
||||
4. Try different symbol format variations
|
||||
|
||||
## Testing Symbols:
|
||||
|
||||
You can test if a symbol works by:
|
||||
1. Opening a chart with that symbol
|
||||
2. If chart opens successfully, the symbol name is correct
|
||||
3. Use that exact symbol name in the EA inputs
|
||||
@@ -0,0 +1,607 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| PerformanceEvaluator.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"
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Performance Metrics Structure |
|
||||
//+------------------------------------------------------------------+
|
||||
struct StrategyPerformance {
|
||||
string strategyName;
|
||||
string symbol; // Store symbol to determine if it's a stock
|
||||
int magicNumber;
|
||||
double initialLotSize;
|
||||
double currentLotSize;
|
||||
double quarterProfit;
|
||||
double quarterTrades;
|
||||
double quarterWins;
|
||||
double quarterLosses;
|
||||
double maxDrawdown;
|
||||
double winRate;
|
||||
datetime quarterStart;
|
||||
datetime quarterEnd;
|
||||
bool isActive;
|
||||
bool inPenaltyMode; // True if strategy is in penalty (worst performer)
|
||||
double lotSizeBeforePenalty; // Store lot size before penalty
|
||||
datetime penaltyStartTime; // When penalty started
|
||||
};
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Global Performance Tracking |
|
||||
//+------------------------------------------------------------------+
|
||||
StrategyPerformance strategyPerformances[];
|
||||
int totalStrategies = 0;
|
||||
datetime lastMonthCheck = 0;
|
||||
datetime currentMonthStart = 0;
|
||||
datetime currentMonthEnd = 0;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Performance Adjustment Parameters |
|
||||
//+------------------------------------------------------------------+
|
||||
input group "=== Performance Evaluation Settings ==="
|
||||
input bool PE_EnableAutoAdjustment = true; // Enable automatic lot size adjustment
|
||||
input double PE_LotSizeIncreasePercent = 10.0; // % increase for top-ranked strategies
|
||||
input double PE_LotSizeDecreasePercent = 10.0; // % decrease for bottom-ranked strategies
|
||||
input double PE_MinLotSize = 0.01; // Minimum lot size for forex/crypto
|
||||
input double PE_MinLotSizeStocks = 5.0; // Minimum lot size for stocks (5-10 range)
|
||||
input double PE_MaxLotSize = 100.0; // Maximum lot size after adjustment
|
||||
input int PE_TopPerformersCount = 3; // Number of top strategies to increase lot size
|
||||
input int PE_BottomPerformersCount = 3; // Number of bottom strategies to decrease lot size
|
||||
input bool PE_UseWinRateWeight = true; // Consider win rate in ranking (50% profit, 50% win rate)
|
||||
input bool PE_EnableBlitzPlay = true; // Enable blitz play: worst performer gets minimum lot size penalty
|
||||
input bool PE_EnableLogging = true; // Enable performance logging
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialize Performance Tracking |
|
||||
//+------------------------------------------------------------------+
|
||||
void InitPerformanceTracking()
|
||||
{
|
||||
// Calculate current month dates
|
||||
MqlDateTime dt;
|
||||
TimeToStruct(TimeCurrent(), dt);
|
||||
|
||||
// Determine month start (first day of current month)
|
||||
dt.day = 1;
|
||||
dt.hour = 0;
|
||||
dt.min = 0;
|
||||
dt.sec = 0;
|
||||
currentMonthStart = StructToTime(dt);
|
||||
|
||||
// Calculate month end (first day of next month - 1 second)
|
||||
dt.mon += 1;
|
||||
if(dt.mon > 12)
|
||||
{
|
||||
dt.mon = 1;
|
||||
dt.year++;
|
||||
}
|
||||
currentMonthEnd = StructToTime(dt) - 1; // End of last day of month
|
||||
|
||||
lastMonthCheck = TimeCurrent();
|
||||
|
||||
if(PE_EnableLogging)
|
||||
{
|
||||
Print("Performance Evaluator: Initialized");
|
||||
Print("Current Month Start: ", TimeToString(currentMonthStart));
|
||||
Print("Current Month End: ", TimeToString(currentMonthEnd));
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check if Symbol is a Stock |
|
||||
//+------------------------------------------------------------------+
|
||||
bool IsStockSymbol(string symbol)
|
||||
{
|
||||
// Check if symbol contains common stock indicators
|
||||
if(StringFind(symbol, ".US") >= 0) return true;
|
||||
if(StringFind(symbol, "NASDAQ:") >= 0) return true;
|
||||
if(StringFind(symbol, "NYSE:") >= 0) return true;
|
||||
|
||||
// Note: Symbol category check removed to avoid enum conversion issues
|
||||
// String-based checks (.US, NASDAQ:, NYSE:, common tickers) are sufficient
|
||||
|
||||
// Common stock tickers (without .US suffix)
|
||||
string commonStocks[] = {"AAPL", "NVDA", "TSLA", "GOOGL", "AMZN", "META", "AMD", "NFLX"};
|
||||
for(int i = 0; i < ArraySize(commonStocks); i++)
|
||||
{
|
||||
if(StringFind(symbol, commonStocks[i]) == 0) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get Minimum Lot Size for Symbol |
|
||||
//+------------------------------------------------------------------+
|
||||
double GetMinLotSizeForSymbol(string symbol)
|
||||
{
|
||||
if(IsStockSymbol(symbol))
|
||||
return PE_MinLotSizeStocks;
|
||||
else
|
||||
return PE_MinLotSize;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Register Strategy for Performance Tracking |
|
||||
//+------------------------------------------------------------------+
|
||||
void RegisterStrategy(string strategyName, int magicNumber, double initialLotSize, string symbol = "")
|
||||
{
|
||||
// Check if strategy already registered
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].strategyName == strategyName &&
|
||||
strategyPerformances[i].magicNumber == magicNumber)
|
||||
{
|
||||
if(PE_EnableLogging)
|
||||
Print("Performance Evaluator: Strategy '", strategyName, "' already registered");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Add new strategy
|
||||
int newSize = ArraySize(strategyPerformances) + 1;
|
||||
ArrayResize(strategyPerformances, newSize);
|
||||
|
||||
strategyPerformances[newSize - 1].strategyName = strategyName;
|
||||
strategyPerformances[newSize - 1].symbol = symbol;
|
||||
strategyPerformances[newSize - 1].magicNumber = magicNumber;
|
||||
strategyPerformances[newSize - 1].initialLotSize = initialLotSize;
|
||||
// Start with minimum lot size for safety (symbol-specific minimum)
|
||||
double minLot = GetMinLotSizeForSymbol(symbol);
|
||||
strategyPerformances[newSize - 1].currentLotSize = minLot;
|
||||
strategyPerformances[newSize - 1].quarterProfit = 0.0;
|
||||
strategyPerformances[newSize - 1].quarterTrades = 0;
|
||||
strategyPerformances[newSize - 1].quarterWins = 0;
|
||||
strategyPerformances[newSize - 1].quarterLosses = 0;
|
||||
strategyPerformances[newSize - 1].maxDrawdown = 0.0;
|
||||
strategyPerformances[newSize - 1].winRate = 0.0;
|
||||
strategyPerformances[newSize - 1].quarterStart = currentMonthStart;
|
||||
strategyPerformances[newSize - 1].quarterEnd = currentMonthEnd;
|
||||
strategyPerformances[newSize - 1].isActive = true;
|
||||
strategyPerformances[newSize - 1].inPenaltyMode = false;
|
||||
strategyPerformances[newSize - 1].lotSizeBeforePenalty = initialLotSize;
|
||||
strategyPerformances[newSize - 1].penaltyStartTime = 0;
|
||||
|
||||
totalStrategies = newSize;
|
||||
|
||||
if(PE_EnableLogging)
|
||||
Print("Performance Evaluator: Registered strategy '", strategyName,
|
||||
"' (Magic: ", magicNumber, ", Initial Lot: ", initialLotSize, ")");
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Update Strategy Performance Metrics |
|
||||
//+------------------------------------------------------------------+
|
||||
void UpdateStrategyPerformance(string strategyName, int magicNumber)
|
||||
{
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].strategyName == strategyName &&
|
||||
strategyPerformances[i].magicNumber == magicNumber &&
|
||||
strategyPerformances[i].isActive)
|
||||
{
|
||||
// Calculate performance for current quarter
|
||||
double totalProfit = 0.0;
|
||||
int totalTrades = 0;
|
||||
int wins = 0;
|
||||
int losses = 0;
|
||||
double maxDD = 0.0;
|
||||
double peakBalance = 0.0;
|
||||
|
||||
// Scan all closed deals in current quarter
|
||||
datetime quarterStart = strategyPerformances[i].quarterStart;
|
||||
datetime quarterEnd = strategyPerformances[i].quarterEnd;
|
||||
|
||||
// Select history for the quarter
|
||||
if(HistorySelect(quarterStart, quarterEnd))
|
||||
{
|
||||
int totalDeals = HistoryDealsTotal();
|
||||
for(int j = 0; j < totalDeals; j++)
|
||||
{
|
||||
ulong ticket = HistoryDealGetTicket(j);
|
||||
if(ticket > 0)
|
||||
{
|
||||
long dealMagic = HistoryDealGetInteger(ticket, DEAL_MAGIC);
|
||||
if(dealMagic == magicNumber)
|
||||
{
|
||||
double profit = HistoryDealGetDouble(ticket, DEAL_PROFIT);
|
||||
double swap = HistoryDealGetDouble(ticket, DEAL_SWAP);
|
||||
double commission = HistoryDealGetDouble(ticket, DEAL_COMMISSION);
|
||||
double totalDealProfit = profit + swap + commission;
|
||||
|
||||
totalProfit += totalDealProfit;
|
||||
totalTrades++;
|
||||
|
||||
if(totalDealProfit > 0)
|
||||
wins++;
|
||||
else if(totalDealProfit < 0)
|
||||
losses++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate win rate
|
||||
double winRate = 0.0;
|
||||
if(totalTrades > 0)
|
||||
winRate = (double)wins / (double)totalTrades * 100.0;
|
||||
|
||||
// Update metrics
|
||||
strategyPerformances[i].quarterProfit = totalProfit;
|
||||
strategyPerformances[i].quarterTrades = totalTrades;
|
||||
strategyPerformances[i].quarterWins = wins;
|
||||
strategyPerformances[i].quarterLosses = losses;
|
||||
strategyPerformances[i].winRate = winRate;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Strategy Ranking Structure |
|
||||
//+------------------------------------------------------------------+
|
||||
struct StrategyRank {
|
||||
int index;
|
||||
double score;
|
||||
};
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Calculate Strategy Score for Ranking |
|
||||
//+------------------------------------------------------------------+
|
||||
double CalculateStrategyScore(int strategyIndex)
|
||||
{
|
||||
double profit = strategyPerformances[strategyIndex].quarterProfit;
|
||||
double winRate = strategyPerformances[strategyIndex].winRate;
|
||||
double trades = strategyPerformances[strategyIndex].quarterTrades;
|
||||
|
||||
// Normalize profit (scale to 0-100 range, assuming max profit of $1000)
|
||||
double normalizedProfit = MathMin(profit / 10.0, 100.0);
|
||||
if(profit < 0) normalizedProfit = profit / 5.0; // Penalize losses more
|
||||
|
||||
// Calculate score
|
||||
double score = 0.0;
|
||||
if(PE_UseWinRateWeight)
|
||||
{
|
||||
// 50% profit, 50% win rate (if enough trades)
|
||||
if(trades >= 5)
|
||||
score = (normalizedProfit * 0.5) + (winRate * 0.5);
|
||||
else
|
||||
score = normalizedProfit; // Not enough trades, use profit only
|
||||
}
|
||||
else
|
||||
{
|
||||
// Profit only
|
||||
score = normalizedProfit;
|
||||
}
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check if Month Ended and Evaluate Performance |
|
||||
//+------------------------------------------------------------------+
|
||||
void CheckMonthEnd()
|
||||
{
|
||||
datetime now = TimeCurrent();
|
||||
|
||||
// Check if we've entered a new month
|
||||
if(now >= currentMonthEnd)
|
||||
{
|
||||
if(PE_EnableLogging)
|
||||
Print("Performance Evaluator: Month ended. Evaluating and ranking strategies...");
|
||||
|
||||
// Update performance metrics for all strategies
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].isActive)
|
||||
{
|
||||
UpdateStrategyPerformance(strategyPerformances[i].strategyName,
|
||||
strategyPerformances[i].magicNumber);
|
||||
}
|
||||
}
|
||||
|
||||
// Rank strategies
|
||||
int activeCount = 0;
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].isActive)
|
||||
activeCount++;
|
||||
}
|
||||
|
||||
if(activeCount > 0)
|
||||
{
|
||||
// Create ranking array
|
||||
StrategyRank ranks[];
|
||||
ArrayResize(ranks, activeCount);
|
||||
int rankIndex = 0;
|
||||
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].isActive)
|
||||
{
|
||||
ranks[rankIndex].index = i;
|
||||
ranks[rankIndex].score = CalculateStrategyScore(i);
|
||||
rankIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
// Sort by score (descending - highest score first)
|
||||
for(int i = 0; i < activeCount - 1; i++)
|
||||
{
|
||||
for(int j = i + 1; j < activeCount; j++)
|
||||
{
|
||||
if(ranks[j].score > ranks[i].score)
|
||||
{
|
||||
StrategyRank temp = ranks[i];
|
||||
ranks[i] = ranks[j];
|
||||
ranks[j] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust lot sizes based on ranking
|
||||
if(PE_EnableAutoAdjustment)
|
||||
{
|
||||
// Increase top performers (skip if in penalty mode)
|
||||
int topCount = MathMin(PE_TopPerformersCount, activeCount);
|
||||
for(int i = 0; i < topCount; i++)
|
||||
{
|
||||
int strategyIdx = ranks[i].index;
|
||||
|
||||
// Skip if strategy is in penalty mode
|
||||
if(strategyPerformances[strategyIdx].inPenaltyMode)
|
||||
continue;
|
||||
|
||||
double oldLotSize = strategyPerformances[strategyIdx].currentLotSize;
|
||||
double newLotSize = oldLotSize * (1.0 + PE_LotSizeIncreasePercent / 100.0);
|
||||
|
||||
if(newLotSize > PE_MaxLotSize)
|
||||
newLotSize = PE_MaxLotSize;
|
||||
|
||||
strategyPerformances[strategyIdx].currentLotSize = newLotSize;
|
||||
|
||||
if(PE_EnableLogging)
|
||||
Print("Performance Evaluator: Rank #", (i+1), " - Increasing '",
|
||||
strategyPerformances[strategyIdx].strategyName,
|
||||
"' lot size from ", oldLotSize, " to ", newLotSize,
|
||||
" (Score: ", DoubleToString(ranks[i].score, 2),
|
||||
", Profit: $", DoubleToString(strategyPerformances[strategyIdx].quarterProfit, 2),
|
||||
", Win Rate: ", DoubleToString(strategyPerformances[strategyIdx].winRate, 2), "%)");
|
||||
}
|
||||
|
||||
// Decrease bottom performers (skip worst one if blitz play is enabled)
|
||||
int bottomCount = MathMin(PE_BottomPerformersCount, activeCount);
|
||||
int startIdx = activeCount - bottomCount;
|
||||
|
||||
// If blitz play is enabled, skip the worst performer (it will get minimum penalty)
|
||||
if(PE_EnableBlitzPlay && activeCount > 0)
|
||||
startIdx = activeCount - bottomCount + 1;
|
||||
|
||||
for(int i = startIdx; i < activeCount; i++)
|
||||
{
|
||||
int strategyIdx = ranks[i].index;
|
||||
|
||||
// Skip if strategy is in penalty mode
|
||||
if(strategyPerformances[strategyIdx].inPenaltyMode)
|
||||
continue;
|
||||
|
||||
double oldLotSize = strategyPerformances[strategyIdx].currentLotSize;
|
||||
double newLotSize = oldLotSize * (1.0 - PE_LotSizeDecreasePercent / 100.0);
|
||||
|
||||
// Use symbol-specific minimum lot size
|
||||
double minLot = GetMinLotSizeForSymbol(strategyPerformances[strategyIdx].symbol);
|
||||
if(newLotSize < minLot)
|
||||
newLotSize = minLot;
|
||||
|
||||
strategyPerformances[strategyIdx].currentLotSize = newLotSize;
|
||||
|
||||
if(PE_EnableLogging)
|
||||
Print("Performance Evaluator: Rank #", (i+1), " - Decreasing '",
|
||||
strategyPerformances[strategyIdx].strategyName,
|
||||
"' lot size from ", oldLotSize, " to ", newLotSize,
|
||||
" (Score: ", DoubleToString(ranks[i].score, 2),
|
||||
", Profit: $", DoubleToString(strategyPerformances[strategyIdx].quarterProfit, 2),
|
||||
", Win Rate: ", DoubleToString(strategyPerformances[strategyIdx].winRate, 2), "%)");
|
||||
}
|
||||
}
|
||||
|
||||
// Blitz Play: Apply penalty to worst performer
|
||||
if(PE_EnableBlitzPlay && activeCount > 0)
|
||||
{
|
||||
// Find worst performer (last in ranking)
|
||||
int worstIdx = ranks[activeCount - 1].index;
|
||||
|
||||
// Remove penalty from previous worst performer (if any)
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].isActive && strategyPerformances[i].inPenaltyMode)
|
||||
{
|
||||
// Check if penalty period has passed (one month)
|
||||
if(now - strategyPerformances[i].penaltyStartTime >= 2592000) // ~30 days
|
||||
{
|
||||
// Restore lot size to before penalty
|
||||
strategyPerformances[i].currentLotSize = strategyPerformances[i].lotSizeBeforePenalty;
|
||||
strategyPerformances[i].inPenaltyMode = false;
|
||||
strategyPerformances[i].penaltyStartTime = 0;
|
||||
|
||||
if(PE_EnableLogging)
|
||||
Print("Blitz Play: Penalty removed from '", strategyPerformances[i].strategyName,
|
||||
"'. Lot size restored to ", strategyPerformances[i].currentLotSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply penalty to new worst performer
|
||||
if(!strategyPerformances[worstIdx].inPenaltyMode)
|
||||
{
|
||||
strategyPerformances[worstIdx].lotSizeBeforePenalty = strategyPerformances[worstIdx].currentLotSize;
|
||||
// Use symbol-specific minimum lot size
|
||||
double minLot = GetMinLotSizeForSymbol(strategyPerformances[worstIdx].symbol);
|
||||
strategyPerformances[worstIdx].currentLotSize = minLot;
|
||||
strategyPerformances[worstIdx].inPenaltyMode = true;
|
||||
strategyPerformances[worstIdx].penaltyStartTime = now;
|
||||
|
||||
if(PE_EnableLogging)
|
||||
Print("Blitz Play: WORST PERFORMER - '", strategyPerformances[worstIdx].strategyName,
|
||||
"' penalized! Lot size reduced from ", strategyPerformances[worstIdx].lotSizeBeforePenalty,
|
||||
" to minimum ", minLot, " (Score: ", DoubleToString(ranks[activeCount - 1].score, 2),
|
||||
", Profit: $", DoubleToString(strategyPerformances[worstIdx].quarterProfit, 2), ")");
|
||||
}
|
||||
}
|
||||
|
||||
// Log performance report
|
||||
if(PE_EnableLogging)
|
||||
{
|
||||
Print("=== Monthly Performance Ranking ===");
|
||||
for(int i = 0; i < activeCount; i++)
|
||||
{
|
||||
int strategyIdx = ranks[i].index;
|
||||
Print("Rank #", (i+1), ": ", strategyPerformances[strategyIdx].strategyName,
|
||||
" - Score: ", DoubleToString(ranks[i].score, 2),
|
||||
", Profit: $", DoubleToString(strategyPerformances[strategyIdx].quarterProfit, 2),
|
||||
", Win Rate: ", DoubleToString(strategyPerformances[strategyIdx].winRate, 2), "%",
|
||||
", Trades: ", (int)strategyPerformances[strategyIdx].quarterTrades,
|
||||
", Lot Size: ", DoubleToString(strategyPerformances[strategyIdx].currentLotSize, 2));
|
||||
}
|
||||
Print("===================================");
|
||||
}
|
||||
}
|
||||
|
||||
// Reset month metrics for all strategies
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].isActive)
|
||||
{
|
||||
strategyPerformances[i].quarterProfit = 0.0;
|
||||
strategyPerformances[i].quarterTrades = 0;
|
||||
strategyPerformances[i].quarterWins = 0;
|
||||
strategyPerformances[i].quarterLosses = 0;
|
||||
strategyPerformances[i].maxDrawdown = 0.0;
|
||||
strategyPerformances[i].winRate = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
// Update month dates
|
||||
MqlDateTime dt;
|
||||
TimeToStruct(now, dt);
|
||||
|
||||
// First day of current month
|
||||
dt.day = 1;
|
||||
dt.hour = 0;
|
||||
dt.min = 0;
|
||||
dt.sec = 0;
|
||||
currentMonthStart = StructToTime(dt);
|
||||
|
||||
// First day of next month - 1 second
|
||||
dt.mon += 1;
|
||||
if(dt.mon > 12)
|
||||
{
|
||||
dt.mon = 1;
|
||||
dt.year++;
|
||||
}
|
||||
currentMonthEnd = StructToTime(dt) - 1;
|
||||
|
||||
// Update month dates for all strategies
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
strategyPerformances[i].quarterStart = currentMonthStart;
|
||||
strategyPerformances[i].quarterEnd = currentMonthEnd;
|
||||
}
|
||||
|
||||
lastMonthCheck = now;
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get Current Lot Size for Strategy |
|
||||
//+------------------------------------------------------------------+
|
||||
double GetStrategyLotSize(string strategyName, int magicNumber)
|
||||
{
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].strategyName == strategyName &&
|
||||
strategyPerformances[i].magicNumber == magicNumber &&
|
||||
strategyPerformances[i].isActive)
|
||||
{
|
||||
return strategyPerformances[i].currentLotSize;
|
||||
}
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Process Performance Evaluation (call from OnTick) |
|
||||
//+------------------------------------------------------------------+
|
||||
void ProcessPerformanceEvaluation()
|
||||
{
|
||||
// Check if month ended
|
||||
CheckMonthEnd();
|
||||
|
||||
// Check for penalty expiration (blitz play)
|
||||
if(PE_EnableBlitzPlay)
|
||||
{
|
||||
datetime now = TimeCurrent();
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].isActive && strategyPerformances[i].inPenaltyMode)
|
||||
{
|
||||
// Check if penalty period has passed (one month = ~30 days)
|
||||
if(now - strategyPerformances[i].penaltyStartTime >= 2592000)
|
||||
{
|
||||
// Restore lot size to before penalty
|
||||
strategyPerformances[i].currentLotSize = strategyPerformances[i].lotSizeBeforePenalty;
|
||||
strategyPerformances[i].inPenaltyMode = false;
|
||||
strategyPerformances[i].penaltyStartTime = 0;
|
||||
|
||||
if(PE_EnableLogging)
|
||||
Print("Blitz Play: Penalty expired for '", strategyPerformances[i].strategyName,
|
||||
"'. Lot size restored to ", strategyPerformances[i].currentLotSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update performance metrics periodically (every hour)
|
||||
static datetime lastUpdate = 0;
|
||||
if(TimeCurrent() - lastUpdate >= 3600)
|
||||
{
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].isActive)
|
||||
{
|
||||
UpdateStrategyPerformance(strategyPerformances[i].strategyName,
|
||||
strategyPerformances[i].magicNumber);
|
||||
}
|
||||
}
|
||||
lastUpdate = TimeCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get Performance Summary |
|
||||
//+------------------------------------------------------------------+
|
||||
string GetPerformanceSummary()
|
||||
{
|
||||
string summary = "\n=== Performance Summary ===\n";
|
||||
summary += "Current Month: " + TimeToString(currentMonthStart) + " to " + TimeToString(currentMonthEnd) + "\n\n";
|
||||
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].isActive)
|
||||
{
|
||||
summary += strategyPerformances[i].strategyName + ":\n";
|
||||
summary += " Profit: $" + DoubleToString(strategyPerformances[i].quarterProfit, 2) + "\n";
|
||||
summary += " Trades: " + IntegerToString((int)strategyPerformances[i].quarterTrades) + "\n";
|
||||
summary += " Win Rate: " + DoubleToString(strategyPerformances[i].winRate, 2) + "%\n";
|
||||
summary += " Lot Size: " + DoubleToString(strategyPerformances[i].currentLotSize, 2) + "\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
return summary;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,76 @@
|
||||
# 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")
|
||||
@@ -0,0 +1,300 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| DarvasBoxStrategy.mqh |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
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);
|
||||
dbData.volumeHandle = iVolumes(symbol, PERIOD_CURRENT, 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)
|
||||
{
|
||||
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()
|
||||
{
|
||||
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];
|
||||
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;
|
||||
|
||||
// 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(g_DB_LotSize, dbData.symbol, 0, sl, tp, "Darvas Box Breakout");
|
||||
else
|
||||
result = dbData.trade.Sell(g_DB_LotSize, 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_CURRENT, 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");
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,496 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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))
|
||||
{
|
||||
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))
|
||||
{
|
||||
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");
|
||||
Print("TRACE: Lot: ", g_ES_LotSize);
|
||||
|
||||
bool success = false;
|
||||
|
||||
if(order_type == ORDER_TYPE_BUY)
|
||||
{
|
||||
success = esData.trade.Buy(g_ES_LotSize, esData.symbol, 0, 0, 0, "EMA Crossover Trade");
|
||||
}
|
||||
else
|
||||
{
|
||||
success = esData.trade.Sell(g_ES_LotSize, 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);
|
||||
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;
|
||||
|
||||
double position_profit = PositionGetDouble(POSITION_PROFIT);
|
||||
double position_open_price = PositionGetDouble(POSITION_PRICE_OPEN);
|
||||
double current_price = PositionGetDouble(POSITION_PRICE_CURRENT);
|
||||
ENUM_POSITION_TYPE position_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
|
||||
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;
|
||||
double trailing_stop_pips = ES_TrailingStop;
|
||||
|
||||
//--- Gleitender Stop (Trailing Stop) - nur wenn Position im Profit ist
|
||||
if(position_profit > 0) // Only apply trailing stop when in profit
|
||||
{
|
||||
if(position_type == POSITION_TYPE_BUY)
|
||||
{
|
||||
double new_stop_loss = current_price - (trailing_stop_pips * point * pips_multiplier);
|
||||
double current_stop_loss = PositionGetDouble(POSITION_SL);
|
||||
|
||||
// Only move stop loss if new stop is higher than current stop
|
||||
if(new_stop_loss > current_stop_loss)
|
||||
{
|
||||
ÄndereStopLoss(new_stop_loss);
|
||||
}
|
||||
}
|
||||
else if(position_type == POSITION_TYPE_SELL)
|
||||
{
|
||||
double new_stop_loss = current_price + (trailing_stop_pips * point * pips_multiplier);
|
||||
double current_stop_loss = PositionGetDouble(POSITION_SL);
|
||||
|
||||
// Only move stop loss if new stop is lower than current stop
|
||||
if(new_stop_loss < current_stop_loss || current_stop_loss == 0)
|
||||
{
|
||||
ÄndereStopLoss(new_stop_loss);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--- Ausstieg bei Preis unter/über EMA (Exit when price below/above EMA)
|
||||
if(ArraySize(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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
// Skip if not initialized (symbol not available)
|
||||
if(!esData.isInitialized)
|
||||
return;
|
||||
|
||||
esData.symbol = symbol; // Update symbol in case it changed
|
||||
|
||||
//--- Bar-Daten oder Tick-Daten verwenden (Use bar data or tick data)
|
||||
if(ES_UseBarData)
|
||||
{
|
||||
//--- Nur bei neuen Bars ausführen (Only execute on new bars)
|
||||
datetime current_bar_time = iTime(esData.symbol, ES_Timeframe, 0);
|
||||
|
||||
if(current_bar_time == esData.last_bar_time)
|
||||
{
|
||||
return; // Kein neuer Bar, nichts tun
|
||||
}
|
||||
|
||||
esData.last_bar_time = current_bar_time;
|
||||
}
|
||||
|
||||
//--- EMA Werte berechnen (Calculate EMA values)
|
||||
BerechneEMA();
|
||||
|
||||
//--- Debug: Aktuelle Werte ausgeben (Debug: Output current values)
|
||||
if(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];
|
||||
int digits = (int)SymbolInfoInteger(esData.symbol, SYMBOL_DIGITS);
|
||||
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("==================");
|
||||
}
|
||||
|
||||
//--- Überwachung prüfen (Check monitoring)
|
||||
if(esData.überwachung_aktiv)
|
||||
{
|
||||
if(ES_UseBarData)
|
||||
{
|
||||
// Bar-basierte Überwachungszeit
|
||||
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
|
||||
{
|
||||
// Tick-basierte Überwachungszeit
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--- Trigger-Bedingungen prüfen (Check trigger conditions)
|
||||
PrüfeTrigger();
|
||||
|
||||
//--- Trade Management (Trade management)
|
||||
VerwalteTrades();
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,240 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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]);
|
||||
}
|
||||
|
||||
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.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(!((currentHour < RC_tradingHourOneEnd && currentHour > RC_tradingHourOneBegin) ||
|
||||
(currentHour < RC_tradingHourTwoEnd && currentHour > RC_tradingHourTwoBegin)))
|
||||
{
|
||||
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;
|
||||
double closeCurr = iClose(Symbol(), Period(), 0);
|
||||
double priceToEmaDistance = (closeCurr - currentEMA) * 10;
|
||||
|
||||
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;
|
||||
bool isTrendStrong = MathAbs(emaSlope) > RC_emaSlopeThreshold || MathAbs(priceToEmaDistance) > 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;
|
||||
return;
|
||||
}
|
||||
|
||||
if(currentRSI < RC_overboughtLevel - RC_entryRSISellSpread && rcData.previousRSIDef >= RC_overboughtLevel &&
|
||||
!isSellPosition && !hasPosition && cooldownPassed)
|
||||
{
|
||||
rcData.trade.SetExpertMagicNumber(RC_MagicNumber);
|
||||
if(rcData.trade.Sell(g_RC_LotSize, rcData.symbol, 0.0, 0.0, 0.0, "Sell Order"))
|
||||
{
|
||||
rcData.lastTradeTime = currentTime;
|
||||
}
|
||||
}
|
||||
|
||||
if(currentRSI > RC_oversoldLevel + RC_entryRSIBuySpread && rcData.previousRSIDef <= RC_oversoldLevel &&
|
||||
!isBuyPosition && !hasPosition && cooldownPassed)
|
||||
{
|
||||
rcData.trade.SetExpertMagicNumber(RC_MagicNumber);
|
||||
if(rcData.trade.Buy(g_RC_LotSize, rcData.symbol, 0.0, 0.0, 0.0, "Buy Order"))
|
||||
{
|
||||
rcData.lastTradeTime = currentTime;
|
||||
}
|
||||
}
|
||||
|
||||
rcData.previousRSIDef = currentRSI;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,471 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| RSIMidPointHijackStrategy.mqh |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
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);
|
||||
rmData.trade.Sell(g_RM_LotSize, 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);
|
||||
rmData.trade.Buy(g_RM_LotSize, 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);
|
||||
rmData.trade.Sell(g_RM_LotSize, 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);
|
||||
rmData.trade.Buy(g_RM_LotSize, 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);
|
||||
rmData.trade.Buy(g_RM_LotSize, 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);
|
||||
rmData.trade.Sell(g_RM_LotSize, 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);
|
||||
rmData.trade.Buy(g_RM_LotSize, 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);
|
||||
rmData.trade.Sell(g_RM_LotSize, 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);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,493 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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)
|
||||
{
|
||||
// Check if market is open
|
||||
long tradeMode = SymbolInfoInteger(data.symbol, SYMBOL_TRADE_MODE);
|
||||
if(tradeMode != 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(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.SetTypeFilling(ORDER_FILLING_IOC);
|
||||
|
||||
// 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;
|
||||
|
||||
// Set trade parameters
|
||||
data.trade.SetDeviationInPoints(data.Slippage);
|
||||
data.trade.SetTypeFilling(ORDER_FILLING_IOC);
|
||||
data.trade.SetExpertMagicNumber(data.MagicNumber);
|
||||
|
||||
// Use dynamic lot size
|
||||
double tradeLotSize = lotSize > 0 ? lotSize : data.MaxLotSize;
|
||||
|
||||
// Place buy order using CTrade
|
||||
if(data.trade.Buy(tradeLotSize, 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;
|
||||
|
||||
// Set trade parameters
|
||||
data.trade.SetDeviationInPoints(data.Slippage);
|
||||
data.trade.SetTypeFilling(ORDER_FILLING_IOC);
|
||||
data.trade.SetExpertMagicNumber(data.MagicNumber);
|
||||
|
||||
// Use dynamic lot size
|
||||
double tradeLotSize = lotSize > 0 ? lotSize : data.MaxLotSize;
|
||||
|
||||
// Place sell order using CTrade
|
||||
if(data.trade.Sell(tradeLotSize, data.symbol, currentBid, sl, tp, "RSI Overbought Crossover Sell"))
|
||||
{
|
||||
data.isPositionOpen = true;
|
||||
data.positionOpenPrice = currentBid;
|
||||
data.positionOpenTime = TimeCurrent();
|
||||
data.lastPositionType = POSITION_TYPE_SELL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,451 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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;
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
double minLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
|
||||
double maxLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
|
||||
double lotStep = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
|
||||
|
||||
// Round to lot step
|
||||
if(lotStep > 0)
|
||||
lotSize = MathFloor(lotSize / lotStep) * lotStep;
|
||||
|
||||
// Apply min/max constraints
|
||||
if(lotSize < minLot)
|
||||
lotSize = minLot;
|
||||
if(lotSize > maxLot)
|
||||
lotSize = maxLot;
|
||||
|
||||
return 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)
|
||||
{
|
||||
// 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;
|
||||
|
||||
datetime current_bar_time = iTime(data.symbol, TimeFrame, 0);
|
||||
if(current_bar_time == data.last_bar_time)
|
||||
return;
|
||||
|
||||
data.last_bar_time = current_bar_time;
|
||||
|
||||
if(!UpdateRSI(data))
|
||||
return;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,675 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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.07"
|
||||
#property strict
|
||||
|
||||
#include <Trade\Trade.mqh>
|
||||
#include <Trade\PositionInfo.mqh>
|
||||
#include <Indicators\Trend.mqh>
|
||||
#include <Indicators\Volumes.mqh>
|
||||
#include "MagicNumberHelpers.mqh"
|
||||
|
||||
// Lot globals must exist before strategy .mqh (Darvas uses g_DB_LotSize; EMA/RC/RM use g_ES/g_RC/g_RM)
|
||||
double g_ES_LotSize;
|
||||
double g_RC_LotSize;
|
||||
double g_RM_LotSize;
|
||||
double g_DB_LotSize;
|
||||
double g_DynMultLast = 1.0;
|
||||
|
||||
// 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/RSIReversalAsianStrategy.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 EnableRSIScalpingNVDA = true;
|
||||
input bool EnableRSIScalpingTSLA = true;
|
||||
input bool EnableRSIScalpingXAUUSD = true;
|
||||
input bool EnableRSIReversalAsianEURUSD = true;
|
||||
input bool EnableRSIReversalAsianAUDUSD = true;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Dynamic lot sizing — scale base lots vs reference deposit |
|
||||
//| mult=(equity/ref)^exp; maxMult<=0 上不封顶; minMult<=0 不锁下限 |
|
||||
//+------------------------------------------------------------------+
|
||||
input group "=== Dynamic lot sizing (动态手数) ==="
|
||||
input bool InpDynamicLotEnable = true; // Enable balance/equity-based scaling
|
||||
input double InpDynamicRefDeposit = 3000.0; // Reference balance (match Tester initial deposit)
|
||||
input double InpDynamicExponent = 1.15; // 1.0=linear; >1 faster growth; <1 conservative
|
||||
input double InpDynamicMinMult = 0.0; // <=0 不锁下限; >0 例如0.25 为最低倍数
|
||||
input double InpDynamicMaxMult = 0.0; // <=0 动态倍数不封顶; >0 上限封顶
|
||||
input bool InpDynamicUseEquity = true; // true=ACCOUNT_EQUITY, false=ACCOUNT_BALANCE
|
||||
input double InpDynamicStockLotCap = 0.0; // Extra cap for stock CFDs (0 = none)
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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;
|
||||
input double DB_BaseLotSize = 0.01; // Base lot at InpDynamicRefDeposit (Darvas)
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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 = 250.0;
|
||||
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;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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 |
|
||||
//| - 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 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;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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;
|
||||
};
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Global Variables - RSI Reversal Asian |
|
||||
//+------------------------------------------------------------------+
|
||||
RSIReversalAsianData rraEURUSDData;
|
||||
RSIReversalAsianData rraAUDUSDData;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Dynamic lot helpers |
|
||||
//+------------------------------------------------------------------+
|
||||
double DynClamp(const double v, const double lo, const double hi)
|
||||
{
|
||||
return MathMax(lo, MathMin(hi, v));
|
||||
}
|
||||
|
||||
// maxMult<=0: no ceiling. minMult<=0: no floor on raw (equity/ref)^exp.
|
||||
double ApplyDynamicMultClamp(const double mult)
|
||||
{
|
||||
double m = mult;
|
||||
if(InpDynamicMinMult > 0.0)
|
||||
m = MathMax(m, InpDynamicMinMult);
|
||||
if(InpDynamicMaxMult > 0.0)
|
||||
m = MathMin(m, InpDynamicMaxMult);
|
||||
return m;
|
||||
}
|
||||
|
||||
double NormalizeVolumeForSymbol(const string symbol, double lots)
|
||||
{
|
||||
double minL = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
|
||||
double maxL = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
|
||||
double step = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
|
||||
if(step > 0.0)
|
||||
lots = MathFloor(lots / step + 1e-12) * step;
|
||||
if(lots < minL) lots = minL;
|
||||
if(lots > maxL) lots = maxL;
|
||||
return lots;
|
||||
}
|
||||
|
||||
double GetDynamicMultiplier()
|
||||
{
|
||||
if(!InpDynamicLotEnable)
|
||||
return 1.0;
|
||||
double cap = InpDynamicUseEquity ? AccountInfoDouble(ACCOUNT_EQUITY) : AccountInfoDouble(ACCOUNT_BALANCE);
|
||||
if(cap <= 0.0)
|
||||
cap = InpDynamicRefDeposit;
|
||||
double refv = MathMax(InpDynamicRefDeposit, 1.0);
|
||||
double ratio = cap / refv;
|
||||
if(ratio <= 0.0)
|
||||
ratio = 1.0;
|
||||
double mult = MathPow(ratio, InpDynamicExponent);
|
||||
return ApplyDynamicMultClamp(mult);
|
||||
}
|
||||
|
||||
// baseLot = size at reference deposit; optionalCap 0 = no extra ceiling (broker min/max still apply)
|
||||
double DynamicLotForSymbol(const string symbol, const double baseLot, const double optionalCap = 0.0)
|
||||
{
|
||||
double mult = GetDynamicMultiplier();
|
||||
g_DynMultLast = mult;
|
||||
double v = baseLot * mult;
|
||||
if(optionalCap > 0.0 && v > optionalCap)
|
||||
v = optionalCap;
|
||||
return NormalizeVolumeForSymbol(symbol, v);
|
||||
}
|
||||
|
||||
void RefreshDynamicStrategyLots()
|
||||
{
|
||||
if(!InpDynamicLotEnable)
|
||||
{
|
||||
g_ES_LotSize = NormalizeVolumeForSymbol(ES_Symbol, ES_LotGröße);
|
||||
g_RC_LotSize = NormalizeVolumeForSymbol(RC_Symbol, RC_lotSize);
|
||||
g_RM_LotSize = NormalizeVolumeForSymbol(RM_Symbol, RM_InpLotSize);
|
||||
g_DB_LotSize = NormalizeVolumeForSymbol(DB_Symbol, DB_BaseLotSize);
|
||||
g_DynMultLast = 1.0;
|
||||
return;
|
||||
}
|
||||
g_ES_LotSize = DynamicLotForSymbol(ES_Symbol, ES_LotGröße);
|
||||
g_RC_LotSize = DynamicLotForSymbol(RC_Symbol, RC_lotSize);
|
||||
g_RM_LotSize = DynamicLotForSymbol(RM_Symbol, RM_InpLotSize);
|
||||
g_DB_LotSize = DynamicLotForSymbol(DB_Symbol, DB_BaseLotSize);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Expert initialization function |
|
||||
//+------------------------------------------------------------------+
|
||||
int OnInit()
|
||||
{
|
||||
int initResult = INIT_SUCCEEDED;
|
||||
|
||||
RefreshDynamicStrategyLots();
|
||||
|
||||
// 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);
|
||||
|
||||
// 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, RRA_EURUSD_MaxLotSize,
|
||||
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, RRA_AUDUSD_MaxLotSize,
|
||||
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, "'");
|
||||
|
||||
string acctCur = AccountInfoString(ACCOUNT_CURRENCY);
|
||||
double eq0 = AccountInfoDouble(ACCOUNT_EQUITY);
|
||||
double refvInit = MathMax(InpDynamicRefDeposit, 1.0);
|
||||
double capInit = InpDynamicUseEquity ? eq0 : AccountInfoDouble(ACCOUNT_BALANCE);
|
||||
if(capInit <= 0.0)
|
||||
capInit = refvInit;
|
||||
double ratioInit = capInit / refvInit;
|
||||
double rawPowInit = MathPow(ratioInit, InpDynamicExponent);
|
||||
Print("United EA v1.07 ", acctCur, " equity=", DoubleToString(eq0, 2), " equity/ref=", DoubleToString(ratioInit, 6),
|
||||
" raw^exp=", DoubleToString(rawPowInit, 6), " multOut=", DoubleToString(g_DynMultLast, 6),
|
||||
" minM=", InpDynamicMinMult, " maxM=", InpDynamicMaxMult, " ref=", InpDynamicRefDeposit, " exp=", InpDynamicExponent,
|
||||
" lots ES=", g_ES_LotSize, " RC=", g_RC_LotSize, " RM=", g_RM_LotSize, " DB=", g_DB_LotSize);
|
||||
Print("United EA initialized. Active strategies: ",
|
||||
(EnableDarvasBox ? "DarvasBox " : ""),
|
||||
(EnableEMASlopeDistance ? "EMASlope " : ""),
|
||||
(EnableRSICrossOverReversal ? "RSICrossOver " : ""),
|
||||
(EnableRSIMidPointHijack ? "RSIMidPoint " : ""),
|
||||
(EnableRSIScalpingAPPL ? "RSIScalpingAPPL " : ""),
|
||||
(EnableRSIScalpingBTCUSD ? "RSIScalpingBTCUSD " : ""),
|
||||
(EnableRSIScalpingNVDA ? "RSIScalpingNVDA " : ""),
|
||||
(EnableRSIScalpingTSLA ? "RSIScalpingTSLA " : ""),
|
||||
(EnableRSIScalpingXAUUSD ? "RSIScalpingXAUUSD " : ""),
|
||||
(EnableRSIReversalAsianEURUSD ? "RSIReversalAsianEURUSD " : ""),
|
||||
(EnableRSIReversalAsianAUDUSD ? "RSIReversalAsianAUDUSD " : ""));
|
||||
|
||||
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(EnableRSIReversalAsianEURUSD)
|
||||
DeinitRSIReversalAsian(rraEURUSDData);
|
||||
|
||||
if(EnableRSIReversalAsianAUDUSD)
|
||||
DeinitRSIReversalAsian(rraAUDUSDData);
|
||||
|
||||
Print("United EA deinitialized. Reason: ", reason);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Expert tick function |
|
||||
//+------------------------------------------------------------------+
|
||||
void OnTick()
|
||||
{
|
||||
RefreshDynamicStrategyLots();
|
||||
|
||||
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,
|
||||
DynamicLotForSymbol(RS_APPL_Symbol, RS_APPL_LotSize, InpDynamicStockLotCap),
|
||||
RS_APPL_MagicNumber);
|
||||
|
||||
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, DynamicLotForSymbol(RS_BTCUSD_Symbol, RS_BTCUSD_LotSize), RS_BTCUSD_MagicNumber);
|
||||
|
||||
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,
|
||||
DynamicLotForSymbol(RS_NVDA_Symbol, RS_NVDA_LotSize, InpDynamicStockLotCap),
|
||||
RS_NVDA_MagicNumber);
|
||||
|
||||
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,
|
||||
DynamicLotForSymbol(RS_TSLA_Symbol, RS_TSLA_LotSize, InpDynamicStockLotCap),
|
||||
RS_TSLA_MagicNumber);
|
||||
|
||||
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, DynamicLotForSymbol(RS_XAUUSD_Symbol, RS_XAUUSD_LotSize), RS_XAUUSD_MagicNumber);
|
||||
|
||||
if(EnableRSIReversalAsianEURUSD)
|
||||
ProcessRSIReversalAsian(rraEURUSDData, DynamicLotForSymbol(RRA_EURUSD_Symbol, RRA_EURUSD_MaxLotSize));
|
||||
|
||||
if(EnableRSIReversalAsianAUDUSD)
|
||||
ProcessRSIReversalAsian(rraAUDUSDData, DynamicLotForSymbol(RRA_AUDUSD_Symbol, RRA_AUDUSD_MaxLotSize));
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
@@ -0,0 +1,641 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| UnitedEA.mq5 |
|
||||
//| Copyright 2025, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2025, MetaQuotes Ltd."
|
||||
#property link "https://www.mql5.com"
|
||||
#property version "1.00"
|
||||
#property strict
|
||||
|
||||
#include <Trade\Trade.mqh>
|
||||
#include <Trade\PositionInfo.mqh>
|
||||
#include <Indicators\Trend.mqh>
|
||||
#include <Indicators\Volumes.mqh>
|
||||
#include "MagicNumberHelpers.mqh"
|
||||
#include "PerformanceEvaluator.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 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 = 250.0;
|
||||
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;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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 |
|
||||
//| - 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 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;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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;
|
||||
};
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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 rsNVDAData;
|
||||
RSIScalpingData rsTSLAData;
|
||||
RSIScalpingData rsXAUUSDData;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Global Variables for Dynamic Lot Sizes |
|
||||
//+------------------------------------------------------------------+
|
||||
// All strategies start with minimum lot size for safety (will be adjusted by performance evaluator)
|
||||
double g_DB_LotSize = 0.01; // DarvasBox uses fixed lot size
|
||||
double g_ES_LotSize = 0.01; // EMA Slope Distance - start with minimum
|
||||
double g_RC_LotSize = 0.01; // RSI CrossOver Reversal - start with minimum
|
||||
double g_RM_LotSize = 0.01; // RSI MidPoint Hijack - start with minimum
|
||||
double g_RS_APPL_LotSize = 5.0; // Stock - start with stock minimum (5.0)
|
||||
double g_RS_BTCUSD_LotSize = 0.01; // Crypto - start with forex minimum (0.01)
|
||||
double g_RS_NVDA_LotSize = 5.0; // Stock - start with stock minimum (5.0)
|
||||
double g_RS_TSLA_LotSize = 5.0; // Stock - start with stock minimum (5.0)
|
||||
double g_RS_XAUUSD_LotSize = 0.01; // Forex - start with forex minimum (0.01)
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Expert initialization function |
|
||||
//+------------------------------------------------------------------+
|
||||
int OnInit()
|
||||
{
|
||||
int initResult = INIT_SUCCEEDED;
|
||||
|
||||
// Initialize Performance Evaluator
|
||||
InitPerformanceTracking();
|
||||
|
||||
// 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, "'");
|
||||
else
|
||||
RegisterStrategy("DarvasBox", DB_MagicNumber, 0.01, DB_Symbol); // Fixed lot size
|
||||
}
|
||||
|
||||
if(EnableEMASlopeDistance)
|
||||
{
|
||||
if(!InitEMASlopeDistance(ES_Symbol))
|
||||
Print("Warning: EMASlopeDistance strategy failed to initialize for symbol '", ES_Symbol, "'");
|
||||
else
|
||||
{
|
||||
RegisterStrategy("EMASlopeDistance", ES_MagicNumber, ES_LotGröße, ES_Symbol);
|
||||
// Start with minimum lot size (will be adjusted by performance evaluator)
|
||||
double minLot = GetMinLotSizeForSymbol(ES_Symbol);
|
||||
g_ES_LotSize = minLot;
|
||||
}
|
||||
}
|
||||
|
||||
if(EnableRSICrossOverReversal)
|
||||
{
|
||||
if(!InitRSICrossOverReversal(RC_Symbol))
|
||||
Print("Warning: RSICrossOverReversal strategy failed to initialize for symbol '", RC_Symbol, "'");
|
||||
else
|
||||
{
|
||||
RegisterStrategy("RSICrossOverReversal", RC_MagicNumber, RC_lotSize, RC_Symbol);
|
||||
// Start with minimum lot size (will be adjusted by performance evaluator)
|
||||
double minLot = GetMinLotSizeForSymbol(RC_Symbol);
|
||||
g_RC_LotSize = minLot;
|
||||
}
|
||||
}
|
||||
|
||||
if(EnableRSIMidPointHijack)
|
||||
{
|
||||
if(!InitRSIMidPointHijack(RM_Symbol))
|
||||
Print("Warning: RSIMidPointHijack strategy failed to initialize for symbol '", RM_Symbol, "'");
|
||||
else
|
||||
{
|
||||
RegisterStrategy("RSIMidPointHijack", RM_InpMagicNumberRSIFollow, RM_InpLotSize, RM_Symbol);
|
||||
RegisterStrategy("RSIMidPointHijack_Reverse", RM_InpMagicNumberRSIReverse, RM_InpLotSize, RM_Symbol);
|
||||
RegisterStrategy("RSIMidPointHijack_EMACross", RM_InpMagicNumberEMACross, RM_InpLotSize, RM_Symbol);
|
||||
// Start with minimum lot size (will be adjusted by performance evaluator)
|
||||
double minLot = GetMinLotSizeForSymbol(RM_Symbol);
|
||||
g_RM_LotSize = minLot;
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
RegisterStrategy("RSIScalpingAPPL", RS_APPL_MagicNumber, RS_APPL_LotSize, RS_APPL_Symbol);
|
||||
// Start with minimum lot size (will be adjusted by performance evaluator)
|
||||
double minLot = GetMinLotSizeForSymbol(RS_APPL_Symbol);
|
||||
g_RS_APPL_LotSize = minLot;
|
||||
}
|
||||
|
||||
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);
|
||||
RegisterStrategy("RSIScalpingBTCUSD", RS_BTCUSD_MagicNumber, RS_BTCUSD_LotSize, RS_BTCUSD_Symbol);
|
||||
// Start with minimum lot size (will be adjusted by performance evaluator)
|
||||
double minLot = GetMinLotSizeForSymbol(RS_BTCUSD_Symbol);
|
||||
g_RS_BTCUSD_LotSize = minLot;
|
||||
}
|
||||
|
||||
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);
|
||||
RegisterStrategy("RSIScalpingNVDA", RS_NVDA_MagicNumber, RS_NVDA_LotSize, RS_NVDA_Symbol);
|
||||
// Start with minimum lot size (will be adjusted by performance evaluator)
|
||||
double minLot = GetMinLotSizeForSymbol(RS_NVDA_Symbol);
|
||||
g_RS_NVDA_LotSize = minLot;
|
||||
}
|
||||
|
||||
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);
|
||||
RegisterStrategy("RSIScalpingTSLA", RS_TSLA_MagicNumber, RS_TSLA_LotSize, RS_TSLA_Symbol);
|
||||
// Start with minimum lot size (will be adjusted by performance evaluator)
|
||||
double minLot = GetMinLotSizeForSymbol(RS_TSLA_Symbol);
|
||||
g_RS_TSLA_LotSize = minLot;
|
||||
}
|
||||
|
||||
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);
|
||||
RegisterStrategy("RSIScalpingXAUUSD", RS_XAUUSD_MagicNumber, RS_XAUUSD_LotSize, RS_XAUUSD_Symbol);
|
||||
// Start with minimum lot size (will be adjusted by performance evaluator)
|
||||
double minLot = GetMinLotSizeForSymbol(RS_XAUUSD_Symbol);
|
||||
g_RS_XAUUSD_LotSize = minLot;
|
||||
}
|
||||
|
||||
// Load adjusted lot sizes from performance evaluator
|
||||
if(PE_EnableAutoAdjustment)
|
||||
{
|
||||
double adjustedLot;
|
||||
adjustedLot = GetStrategyLotSize("EMASlopeDistance", ES_MagicNumber);
|
||||
if(adjustedLot > 0) g_ES_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSICrossOverReversal", RC_MagicNumber);
|
||||
if(adjustedLot > 0) g_RC_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIMidPointHijack", RM_InpMagicNumberRSIFollow);
|
||||
if(adjustedLot > 0) g_RM_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIScalpingAPPL", RS_APPL_MagicNumber);
|
||||
if(adjustedLot > 0) g_RS_APPL_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIScalpingBTCUSD", RS_BTCUSD_MagicNumber);
|
||||
if(adjustedLot > 0) g_RS_BTCUSD_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIScalpingNVDA", RS_NVDA_MagicNumber);
|
||||
if(adjustedLot > 0) g_RS_NVDA_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIScalpingTSLA", RS_TSLA_MagicNumber);
|
||||
if(adjustedLot > 0) g_RS_TSLA_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIScalpingXAUUSD", RS_XAUUSD_MagicNumber);
|
||||
if(adjustedLot > 0) g_RS_XAUUSD_LotSize = adjustedLot;
|
||||
}
|
||||
|
||||
Print("United EA initialized. Active strategies: ",
|
||||
(EnableDarvasBox ? "DarvasBox " : ""),
|
||||
(EnableEMASlopeDistance ? "EMASlope " : ""),
|
||||
(EnableRSICrossOverReversal ? "RSICrossOver " : ""),
|
||||
(EnableRSIMidPointHijack ? "RSIMidPoint " : ""),
|
||||
(EnableRSIScalpingAPPL ? "RSIScalpingAPPL " : ""),
|
||||
(EnableRSIScalpingBTCUSD ? "RSIScalpingBTCUSD " : ""),
|
||||
(EnableRSIScalpingNVDA ? "RSIScalpingNVDA " : ""),
|
||||
(EnableRSIScalpingTSLA ? "RSIScalpingTSLA " : ""),
|
||||
(EnableRSIScalpingXAUUSD ? "RSIScalpingXAUUSD " : ""));
|
||||
|
||||
if(PE_EnableLogging)
|
||||
Print(GetPerformanceSummary());
|
||||
|
||||
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);
|
||||
|
||||
Print("United EA deinitialized. Reason: ", reason);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Expert tick function |
|
||||
//+------------------------------------------------------------------+
|
||||
void OnTick()
|
||||
{
|
||||
// Process performance evaluation (checks for quarter end and adjusts lot sizes)
|
||||
ProcessPerformanceEvaluation();
|
||||
|
||||
// Update lot sizes from performance evaluator if auto-adjustment is enabled
|
||||
if(PE_EnableAutoAdjustment)
|
||||
{
|
||||
double adjustedLot;
|
||||
adjustedLot = GetStrategyLotSize("EMASlopeDistance", ES_MagicNumber);
|
||||
if(adjustedLot > 0) g_ES_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSICrossOverReversal", RC_MagicNumber);
|
||||
if(adjustedLot > 0) g_RC_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIMidPointHijack", RM_InpMagicNumberRSIFollow);
|
||||
if(adjustedLot > 0) g_RM_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIScalpingAPPL", RS_APPL_MagicNumber);
|
||||
if(adjustedLot > 0) g_RS_APPL_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIScalpingBTCUSD", RS_BTCUSD_MagicNumber);
|
||||
if(adjustedLot > 0) g_RS_BTCUSD_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIScalpingNVDA", RS_NVDA_MagicNumber);
|
||||
if(adjustedLot > 0) g_RS_NVDA_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIScalpingTSLA", RS_TSLA_MagicNumber);
|
||||
if(adjustedLot > 0) g_RS_TSLA_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIScalpingXAUUSD", RS_XAUUSD_MagicNumber);
|
||||
if(adjustedLot > 0) g_RS_XAUUSD_LotSize = adjustedLot;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Include strategy implementations |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "Strategies/DarvasBoxStrategy.mqh"
|
||||
#include "Strategies/EMASlopeDistanceStrategy.mqh"
|
||||
#include "Strategies/RSICrossOverReversalStrategy.mqh"
|
||||
#include "Strategies/RSIMidPointHijackStrategy.mqh"
|
||||
#include "Strategies/RSIScalpingStrategy.mqh"
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,159 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| MagicNumberHelpers.mqh |
|
||||
//| Copyright 2025, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2025, MetaQuotes Ltd."
|
||||
#property link "https://www.mql5.com"
|
||||
#property version "1.00"
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Select position by symbol and magic number |
|
||||
//+------------------------------------------------------------------+
|
||||
bool PositionSelectByMagic(string symbol, ulong magic_number)
|
||||
{
|
||||
// First try to find position by symbol
|
||||
if(!PositionSelect(symbol))
|
||||
return false;
|
||||
|
||||
// Check if the selected position has the correct magic number
|
||||
if(PositionGetInteger(POSITION_MAGIC) != magic_number)
|
||||
{
|
||||
// Position exists but wrong magic number, search all positions
|
||||
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
||||
{
|
||||
if(PositionGetTicket(i) > 0)
|
||||
{
|
||||
if(PositionGetString(POSITION_SYMBOL) == symbol &&
|
||||
PositionGetInteger(POSITION_MAGIC) == magic_number)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Select position by ticket and verify magic number and symbol |
|
||||
//+------------------------------------------------------------------+
|
||||
bool PositionSelectByTicketAndMagic(ulong ticket, ulong magic_number)
|
||||
{
|
||||
if(!PositionSelectByTicket(ticket))
|
||||
return false;
|
||||
|
||||
return (PositionGetInteger(POSITION_MAGIC) == magic_number);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Select position by ticket and verify symbol, magic number |
|
||||
//+------------------------------------------------------------------+
|
||||
bool PositionSelectByTicketSymbolAndMagic(ulong ticket, string symbol, ulong magic_number)
|
||||
{
|
||||
if(!PositionSelectByTicket(ticket))
|
||||
return false;
|
||||
|
||||
return (PositionGetString(POSITION_SYMBOL) == symbol &&
|
||||
PositionGetInteger(POSITION_MAGIC) == magic_number);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check if position exists with correct magic number |
|
||||
//+------------------------------------------------------------------+
|
||||
bool PositionExistsByMagic(string symbol, ulong magic_number)
|
||||
{
|
||||
return PositionSelectByMagic(symbol, magic_number);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get position ticket by symbol and magic number |
|
||||
//+------------------------------------------------------------------+
|
||||
ulong GetPositionTicketByMagic(string symbol, ulong magic_number)
|
||||
{
|
||||
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
||||
{
|
||||
ulong ticket = PositionGetTicket(i);
|
||||
if(ticket > 0)
|
||||
{
|
||||
if(PositionGetString(POSITION_SYMBOL) == symbol &&
|
||||
PositionGetInteger(POSITION_MAGIC) == magic_number)
|
||||
{
|
||||
return ticket;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Close position by symbol and magic number |
|
||||
//+------------------------------------------------------------------+
|
||||
bool ClosePositionByMagic(CTrade &trade_obj, string symbol, ulong magic_number)
|
||||
{
|
||||
ulong ticket = GetPositionTicketByMagic(symbol, magic_number);
|
||||
if(ticket == 0)
|
||||
return false;
|
||||
|
||||
return trade_obj.PositionClose(ticket);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Modify position by symbol and magic number |
|
||||
//+------------------------------------------------------------------+
|
||||
bool ModifyPositionByMagic(CTrade &trade_obj, string symbol, ulong magic_number,
|
||||
double sl, double tp)
|
||||
{
|
||||
ulong ticket = GetPositionTicketByMagic(symbol, magic_number);
|
||||
if(ticket == 0)
|
||||
return false;
|
||||
|
||||
return trade_obj.PositionModify(ticket, sl, tp);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get position profit by symbol and magic number |
|
||||
//+------------------------------------------------------------------+
|
||||
double GetPositionProfitByMagic(string symbol, ulong magic_number)
|
||||
{
|
||||
if(!PositionSelectByMagic(symbol, magic_number))
|
||||
return 0.0;
|
||||
|
||||
return PositionGetDouble(POSITION_PROFIT);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get position type by symbol and magic number |
|
||||
//+------------------------------------------------------------------+
|
||||
ENUM_POSITION_TYPE GetPositionTypeByMagic(string symbol, ulong magic_number)
|
||||
{
|
||||
if(!PositionSelectByMagic(symbol, magic_number))
|
||||
return WRONG_VALUE;
|
||||
|
||||
return (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Count positions by symbol and magic number |
|
||||
//+------------------------------------------------------------------+
|
||||
int CountPositionsByMagic(string symbol, ulong magic_number)
|
||||
{
|
||||
int count = 0;
|
||||
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
||||
{
|
||||
ulong ticket = PositionGetTicket(i);
|
||||
if(ticket > 0)
|
||||
{
|
||||
if(PositionGetString(POSITION_SYMBOL) == symbol &&
|
||||
PositionGetInteger(POSITION_MAGIC) == magic_number)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,75 @@
|
||||
# Pepperstone US - Symbol Setup Guide
|
||||
|
||||
## Finding Correct Symbol Names in MetaTrader 5
|
||||
|
||||
### Step-by-Step Instructions:
|
||||
|
||||
1. **Open Market Watch Window**
|
||||
- Press `Ctrl+M` or go to `View > Market Watch`
|
||||
|
||||
2. **Show All Symbols**
|
||||
- Right-click in the Market Watch window
|
||||
- Select `Show All` or `Symbols`
|
||||
- This shows all available symbols from your broker
|
||||
|
||||
3. **Search for Your Symbols**
|
||||
- Use the search box in the Market Watch window
|
||||
- Search for: "AAPL", "MSFT", "NVDA", "TSLA", "BTCUSD", "XAUUSD"
|
||||
|
||||
4. **Note the Exact Symbol Name**
|
||||
- The symbol name shown in Market Watch is what you need to use
|
||||
- Common formats for Pepperstone US:
|
||||
- Stocks: `AAPL.US`, `MSFT.US`, `NVDA.US`, `TSLA.US`
|
||||
- Or: `NASDAQ:AAPL`, `NASDAQ:MSFT`, etc.
|
||||
- Or: Just `AAPL`, `MSFT`, etc. (if available)
|
||||
|
||||
5. **Add to Market Watch**
|
||||
- Double-click the symbol to add it to your Market Watch
|
||||
- Or right-click and select `Show`
|
||||
|
||||
6. **Update EA Inputs**
|
||||
- Open the EA inputs in MetaTrader 5
|
||||
- Update each symbol parameter with the exact name from Market Watch
|
||||
|
||||
## Common Pepperstone US Symbol Formats
|
||||
|
||||
### US Stocks:
|
||||
- **Apple**: `AAPL.US` or `NASDAQ:AAPL` or `AAPL`
|
||||
- **Microsoft**: `MSFT.US` or `NASDAQ:MSFT` or `MSFT`
|
||||
- **NVIDIA**: `NVDA.US` or `NASDAQ:NVDA` or `NVDA`
|
||||
- **Tesla**: `TSLA.US` or `NASDAQ:TSLA` or `TSLA`
|
||||
|
||||
### Cryptocurrencies:
|
||||
- **Bitcoin**: `BTCUSD` or `BTC/USD` or `BTCUSD.c`
|
||||
|
||||
### Precious Metals:
|
||||
- **Gold**: `XAUUSD` or `GOLD` or `XAU/USD`
|
||||
|
||||
## Important Notes:
|
||||
|
||||
1. **Symbol Names are Case-Sensitive**: Use exact capitalization
|
||||
2. **Add Symbols to Market Watch**: Symbols must be in Market Watch for the EA to access them
|
||||
3. **Check Trading Hours**: US stocks trade during US market hours (9:30 AM - 4:00 PM ET)
|
||||
4. **CFD vs Stock**: Pepperstone offers CFDs on stocks, not actual stocks
|
||||
5. **Spread**: Check the spread for each symbol - some may have wider spreads
|
||||
|
||||
## Troubleshooting:
|
||||
|
||||
### If Symbol Not Found:
|
||||
1. Check if you're connected to Pepperstone US server
|
||||
2. Verify your account type supports the symbol
|
||||
3. Contact Pepperstone support for symbol availability
|
||||
4. Check if symbol requires special account permissions
|
||||
|
||||
### If EA Shows "Symbol Not Available":
|
||||
1. Make sure symbol is added to Market Watch
|
||||
2. Verify symbol name matches exactly (including dots, colons, etc.)
|
||||
3. Check broker connection status
|
||||
4. Try different symbol format variations
|
||||
|
||||
## Testing Symbols:
|
||||
|
||||
You can test if a symbol works by:
|
||||
1. Opening a chart with that symbol
|
||||
2. If chart opens successfully, the symbol name is correct
|
||||
3. Use that exact symbol name in the EA inputs
|
||||
@@ -0,0 +1,607 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| PerformanceEvaluator.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"
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Performance Metrics Structure |
|
||||
//+------------------------------------------------------------------+
|
||||
struct StrategyPerformance {
|
||||
string strategyName;
|
||||
string symbol; // Store symbol to determine if it's a stock
|
||||
int magicNumber;
|
||||
double initialLotSize;
|
||||
double currentLotSize;
|
||||
double quarterProfit;
|
||||
double quarterTrades;
|
||||
double quarterWins;
|
||||
double quarterLosses;
|
||||
double maxDrawdown;
|
||||
double winRate;
|
||||
datetime quarterStart;
|
||||
datetime quarterEnd;
|
||||
bool isActive;
|
||||
bool inPenaltyMode; // True if strategy is in penalty (worst performer)
|
||||
double lotSizeBeforePenalty; // Store lot size before penalty
|
||||
datetime penaltyStartTime; // When penalty started
|
||||
};
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Global Performance Tracking |
|
||||
//+------------------------------------------------------------------+
|
||||
StrategyPerformance strategyPerformances[];
|
||||
int totalStrategies = 0;
|
||||
datetime lastMonthCheck = 0;
|
||||
datetime currentMonthStart = 0;
|
||||
datetime currentMonthEnd = 0;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Performance Adjustment Parameters |
|
||||
//+------------------------------------------------------------------+
|
||||
input group "=== Performance Evaluation Settings ==="
|
||||
input bool PE_EnableAutoAdjustment = true; // Enable automatic lot size adjustment
|
||||
input double PE_LotSizeIncreasePercent = 10.0; // % increase for top-ranked strategies
|
||||
input double PE_LotSizeDecreasePercent = 10.0; // % decrease for bottom-ranked strategies
|
||||
input double PE_MinLotSize = 0.01; // Minimum lot size for forex/crypto
|
||||
input double PE_MinLotSizeStocks = 5.0; // Minimum lot size for stocks (5-10 range)
|
||||
input double PE_MaxLotSize = 100.0; // Maximum lot size after adjustment
|
||||
input int PE_TopPerformersCount = 3; // Number of top strategies to increase lot size
|
||||
input int PE_BottomPerformersCount = 3; // Number of bottom strategies to decrease lot size
|
||||
input bool PE_UseWinRateWeight = true; // Consider win rate in ranking (50% profit, 50% win rate)
|
||||
input bool PE_EnableBlitzPlay = true; // Enable blitz play: worst performer gets minimum lot size penalty
|
||||
input bool PE_EnableLogging = true; // Enable performance logging
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialize Performance Tracking |
|
||||
//+------------------------------------------------------------------+
|
||||
void InitPerformanceTracking()
|
||||
{
|
||||
// Calculate current month dates
|
||||
MqlDateTime dt;
|
||||
TimeToStruct(TimeCurrent(), dt);
|
||||
|
||||
// Determine month start (first day of current month)
|
||||
dt.day = 1;
|
||||
dt.hour = 0;
|
||||
dt.min = 0;
|
||||
dt.sec = 0;
|
||||
currentMonthStart = StructToTime(dt);
|
||||
|
||||
// Calculate month end (first day of next month - 1 second)
|
||||
dt.mon += 1;
|
||||
if(dt.mon > 12)
|
||||
{
|
||||
dt.mon = 1;
|
||||
dt.year++;
|
||||
}
|
||||
currentMonthEnd = StructToTime(dt) - 1; // End of last day of month
|
||||
|
||||
lastMonthCheck = TimeCurrent();
|
||||
|
||||
if(PE_EnableLogging)
|
||||
{
|
||||
Print("Performance Evaluator: Initialized");
|
||||
Print("Current Month Start: ", TimeToString(currentMonthStart));
|
||||
Print("Current Month End: ", TimeToString(currentMonthEnd));
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check if Symbol is a Stock |
|
||||
//+------------------------------------------------------------------+
|
||||
bool IsStockSymbol(string symbol)
|
||||
{
|
||||
// Check if symbol contains common stock indicators
|
||||
if(StringFind(symbol, ".US") >= 0) return true;
|
||||
if(StringFind(symbol, "NASDAQ:") >= 0) return true;
|
||||
if(StringFind(symbol, "NYSE:") >= 0) return true;
|
||||
|
||||
// Note: Symbol category check removed to avoid enum conversion issues
|
||||
// String-based checks (.US, NASDAQ:, NYSE:, common tickers) are sufficient
|
||||
|
||||
// Common stock tickers (without .US suffix)
|
||||
string commonStocks[] = {"AAPL", "NVDA", "TSLA", "GOOGL", "AMZN", "META", "AMD", "NFLX"};
|
||||
for(int i = 0; i < ArraySize(commonStocks); i++)
|
||||
{
|
||||
if(StringFind(symbol, commonStocks[i]) == 0) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get Minimum Lot Size for Symbol |
|
||||
//+------------------------------------------------------------------+
|
||||
double GetMinLotSizeForSymbol(string symbol)
|
||||
{
|
||||
if(IsStockSymbol(symbol))
|
||||
return PE_MinLotSizeStocks;
|
||||
else
|
||||
return PE_MinLotSize;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Register Strategy for Performance Tracking |
|
||||
//+------------------------------------------------------------------+
|
||||
void RegisterStrategy(string strategyName, int magicNumber, double initialLotSize, string symbol = "")
|
||||
{
|
||||
// Check if strategy already registered
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].strategyName == strategyName &&
|
||||
strategyPerformances[i].magicNumber == magicNumber)
|
||||
{
|
||||
if(PE_EnableLogging)
|
||||
Print("Performance Evaluator: Strategy '", strategyName, "' already registered");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Add new strategy
|
||||
int newSize = ArraySize(strategyPerformances) + 1;
|
||||
ArrayResize(strategyPerformances, newSize);
|
||||
|
||||
strategyPerformances[newSize - 1].strategyName = strategyName;
|
||||
strategyPerformances[newSize - 1].symbol = symbol;
|
||||
strategyPerformances[newSize - 1].magicNumber = magicNumber;
|
||||
strategyPerformances[newSize - 1].initialLotSize = initialLotSize;
|
||||
// Start with minimum lot size for safety (symbol-specific minimum)
|
||||
double minLot = GetMinLotSizeForSymbol(symbol);
|
||||
strategyPerformances[newSize - 1].currentLotSize = minLot;
|
||||
strategyPerformances[newSize - 1].quarterProfit = 0.0;
|
||||
strategyPerformances[newSize - 1].quarterTrades = 0;
|
||||
strategyPerformances[newSize - 1].quarterWins = 0;
|
||||
strategyPerformances[newSize - 1].quarterLosses = 0;
|
||||
strategyPerformances[newSize - 1].maxDrawdown = 0.0;
|
||||
strategyPerformances[newSize - 1].winRate = 0.0;
|
||||
strategyPerformances[newSize - 1].quarterStart = currentMonthStart;
|
||||
strategyPerformances[newSize - 1].quarterEnd = currentMonthEnd;
|
||||
strategyPerformances[newSize - 1].isActive = true;
|
||||
strategyPerformances[newSize - 1].inPenaltyMode = false;
|
||||
strategyPerformances[newSize - 1].lotSizeBeforePenalty = initialLotSize;
|
||||
strategyPerformances[newSize - 1].penaltyStartTime = 0;
|
||||
|
||||
totalStrategies = newSize;
|
||||
|
||||
if(PE_EnableLogging)
|
||||
Print("Performance Evaluator: Registered strategy '", strategyName,
|
||||
"' (Magic: ", magicNumber, ", Initial Lot: ", initialLotSize, ")");
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Update Strategy Performance Metrics |
|
||||
//+------------------------------------------------------------------+
|
||||
void UpdateStrategyPerformance(string strategyName, int magicNumber)
|
||||
{
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].strategyName == strategyName &&
|
||||
strategyPerformances[i].magicNumber == magicNumber &&
|
||||
strategyPerformances[i].isActive)
|
||||
{
|
||||
// Calculate performance for current quarter
|
||||
double totalProfit = 0.0;
|
||||
int totalTrades = 0;
|
||||
int wins = 0;
|
||||
int losses = 0;
|
||||
double maxDD = 0.0;
|
||||
double peakBalance = 0.0;
|
||||
|
||||
// Scan all closed deals in current quarter
|
||||
datetime quarterStart = strategyPerformances[i].quarterStart;
|
||||
datetime quarterEnd = strategyPerformances[i].quarterEnd;
|
||||
|
||||
// Select history for the quarter
|
||||
if(HistorySelect(quarterStart, quarterEnd))
|
||||
{
|
||||
int totalDeals = HistoryDealsTotal();
|
||||
for(int j = 0; j < totalDeals; j++)
|
||||
{
|
||||
ulong ticket = HistoryDealGetTicket(j);
|
||||
if(ticket > 0)
|
||||
{
|
||||
long dealMagic = HistoryDealGetInteger(ticket, DEAL_MAGIC);
|
||||
if(dealMagic == magicNumber)
|
||||
{
|
||||
double profit = HistoryDealGetDouble(ticket, DEAL_PROFIT);
|
||||
double swap = HistoryDealGetDouble(ticket, DEAL_SWAP);
|
||||
double commission = HistoryDealGetDouble(ticket, DEAL_COMMISSION);
|
||||
double totalDealProfit = profit + swap + commission;
|
||||
|
||||
totalProfit += totalDealProfit;
|
||||
totalTrades++;
|
||||
|
||||
if(totalDealProfit > 0)
|
||||
wins++;
|
||||
else if(totalDealProfit < 0)
|
||||
losses++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate win rate
|
||||
double winRate = 0.0;
|
||||
if(totalTrades > 0)
|
||||
winRate = (double)wins / (double)totalTrades * 100.0;
|
||||
|
||||
// Update metrics
|
||||
strategyPerformances[i].quarterProfit = totalProfit;
|
||||
strategyPerformances[i].quarterTrades = totalTrades;
|
||||
strategyPerformances[i].quarterWins = wins;
|
||||
strategyPerformances[i].quarterLosses = losses;
|
||||
strategyPerformances[i].winRate = winRate;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Strategy Ranking Structure |
|
||||
//+------------------------------------------------------------------+
|
||||
struct StrategyRank {
|
||||
int index;
|
||||
double score;
|
||||
};
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Calculate Strategy Score for Ranking |
|
||||
//+------------------------------------------------------------------+
|
||||
double CalculateStrategyScore(int strategyIndex)
|
||||
{
|
||||
double profit = strategyPerformances[strategyIndex].quarterProfit;
|
||||
double winRate = strategyPerformances[strategyIndex].winRate;
|
||||
double trades = strategyPerformances[strategyIndex].quarterTrades;
|
||||
|
||||
// Normalize profit (scale to 0-100 range, assuming max profit of $1000)
|
||||
double normalizedProfit = MathMin(profit / 10.0, 100.0);
|
||||
if(profit < 0) normalizedProfit = profit / 5.0; // Penalize losses more
|
||||
|
||||
// Calculate score
|
||||
double score = 0.0;
|
||||
if(PE_UseWinRateWeight)
|
||||
{
|
||||
// 50% profit, 50% win rate (if enough trades)
|
||||
if(trades >= 5)
|
||||
score = (normalizedProfit * 0.5) + (winRate * 0.5);
|
||||
else
|
||||
score = normalizedProfit; // Not enough trades, use profit only
|
||||
}
|
||||
else
|
||||
{
|
||||
// Profit only
|
||||
score = normalizedProfit;
|
||||
}
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check if Month Ended and Evaluate Performance |
|
||||
//+------------------------------------------------------------------+
|
||||
void CheckMonthEnd()
|
||||
{
|
||||
datetime now = TimeCurrent();
|
||||
|
||||
// Check if we've entered a new month
|
||||
if(now >= currentMonthEnd)
|
||||
{
|
||||
if(PE_EnableLogging)
|
||||
Print("Performance Evaluator: Month ended. Evaluating and ranking strategies...");
|
||||
|
||||
// Update performance metrics for all strategies
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].isActive)
|
||||
{
|
||||
UpdateStrategyPerformance(strategyPerformances[i].strategyName,
|
||||
strategyPerformances[i].magicNumber);
|
||||
}
|
||||
}
|
||||
|
||||
// Rank strategies
|
||||
int activeCount = 0;
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].isActive)
|
||||
activeCount++;
|
||||
}
|
||||
|
||||
if(activeCount > 0)
|
||||
{
|
||||
// Create ranking array
|
||||
StrategyRank ranks[];
|
||||
ArrayResize(ranks, activeCount);
|
||||
int rankIndex = 0;
|
||||
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].isActive)
|
||||
{
|
||||
ranks[rankIndex].index = i;
|
||||
ranks[rankIndex].score = CalculateStrategyScore(i);
|
||||
rankIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
// Sort by score (descending - highest score first)
|
||||
for(int i = 0; i < activeCount - 1; i++)
|
||||
{
|
||||
for(int j = i + 1; j < activeCount; j++)
|
||||
{
|
||||
if(ranks[j].score > ranks[i].score)
|
||||
{
|
||||
StrategyRank temp = ranks[i];
|
||||
ranks[i] = ranks[j];
|
||||
ranks[j] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust lot sizes based on ranking
|
||||
if(PE_EnableAutoAdjustment)
|
||||
{
|
||||
// Increase top performers (skip if in penalty mode)
|
||||
int topCount = MathMin(PE_TopPerformersCount, activeCount);
|
||||
for(int i = 0; i < topCount; i++)
|
||||
{
|
||||
int strategyIdx = ranks[i].index;
|
||||
|
||||
// Skip if strategy is in penalty mode
|
||||
if(strategyPerformances[strategyIdx].inPenaltyMode)
|
||||
continue;
|
||||
|
||||
double oldLotSize = strategyPerformances[strategyIdx].currentLotSize;
|
||||
double newLotSize = oldLotSize * (1.0 + PE_LotSizeIncreasePercent / 100.0);
|
||||
|
||||
if(newLotSize > PE_MaxLotSize)
|
||||
newLotSize = PE_MaxLotSize;
|
||||
|
||||
strategyPerformances[strategyIdx].currentLotSize = newLotSize;
|
||||
|
||||
if(PE_EnableLogging)
|
||||
Print("Performance Evaluator: Rank #", (i+1), " - Increasing '",
|
||||
strategyPerformances[strategyIdx].strategyName,
|
||||
"' lot size from ", oldLotSize, " to ", newLotSize,
|
||||
" (Score: ", DoubleToString(ranks[i].score, 2),
|
||||
", Profit: $", DoubleToString(strategyPerformances[strategyIdx].quarterProfit, 2),
|
||||
", Win Rate: ", DoubleToString(strategyPerformances[strategyIdx].winRate, 2), "%)");
|
||||
}
|
||||
|
||||
// Decrease bottom performers (skip worst one if blitz play is enabled)
|
||||
int bottomCount = MathMin(PE_BottomPerformersCount, activeCount);
|
||||
int startIdx = activeCount - bottomCount;
|
||||
|
||||
// If blitz play is enabled, skip the worst performer (it will get minimum penalty)
|
||||
if(PE_EnableBlitzPlay && activeCount > 0)
|
||||
startIdx = activeCount - bottomCount + 1;
|
||||
|
||||
for(int i = startIdx; i < activeCount; i++)
|
||||
{
|
||||
int strategyIdx = ranks[i].index;
|
||||
|
||||
// Skip if strategy is in penalty mode
|
||||
if(strategyPerformances[strategyIdx].inPenaltyMode)
|
||||
continue;
|
||||
|
||||
double oldLotSize = strategyPerformances[strategyIdx].currentLotSize;
|
||||
double newLotSize = oldLotSize * (1.0 - PE_LotSizeDecreasePercent / 100.0);
|
||||
|
||||
// Use symbol-specific minimum lot size
|
||||
double minLot = GetMinLotSizeForSymbol(strategyPerformances[strategyIdx].symbol);
|
||||
if(newLotSize < minLot)
|
||||
newLotSize = minLot;
|
||||
|
||||
strategyPerformances[strategyIdx].currentLotSize = newLotSize;
|
||||
|
||||
if(PE_EnableLogging)
|
||||
Print("Performance Evaluator: Rank #", (i+1), " - Decreasing '",
|
||||
strategyPerformances[strategyIdx].strategyName,
|
||||
"' lot size from ", oldLotSize, " to ", newLotSize,
|
||||
" (Score: ", DoubleToString(ranks[i].score, 2),
|
||||
", Profit: $", DoubleToString(strategyPerformances[strategyIdx].quarterProfit, 2),
|
||||
", Win Rate: ", DoubleToString(strategyPerformances[strategyIdx].winRate, 2), "%)");
|
||||
}
|
||||
}
|
||||
|
||||
// Blitz Play: Apply penalty to worst performer
|
||||
if(PE_EnableBlitzPlay && activeCount > 0)
|
||||
{
|
||||
// Find worst performer (last in ranking)
|
||||
int worstIdx = ranks[activeCount - 1].index;
|
||||
|
||||
// Remove penalty from previous worst performer (if any)
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].isActive && strategyPerformances[i].inPenaltyMode)
|
||||
{
|
||||
// Check if penalty period has passed (one month)
|
||||
if(now - strategyPerformances[i].penaltyStartTime >= 2592000) // ~30 days
|
||||
{
|
||||
// Restore lot size to before penalty
|
||||
strategyPerformances[i].currentLotSize = strategyPerformances[i].lotSizeBeforePenalty;
|
||||
strategyPerformances[i].inPenaltyMode = false;
|
||||
strategyPerformances[i].penaltyStartTime = 0;
|
||||
|
||||
if(PE_EnableLogging)
|
||||
Print("Blitz Play: Penalty removed from '", strategyPerformances[i].strategyName,
|
||||
"'. Lot size restored to ", strategyPerformances[i].currentLotSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply penalty to new worst performer
|
||||
if(!strategyPerformances[worstIdx].inPenaltyMode)
|
||||
{
|
||||
strategyPerformances[worstIdx].lotSizeBeforePenalty = strategyPerformances[worstIdx].currentLotSize;
|
||||
// Use symbol-specific minimum lot size
|
||||
double minLot = GetMinLotSizeForSymbol(strategyPerformances[worstIdx].symbol);
|
||||
strategyPerformances[worstIdx].currentLotSize = minLot;
|
||||
strategyPerformances[worstIdx].inPenaltyMode = true;
|
||||
strategyPerformances[worstIdx].penaltyStartTime = now;
|
||||
|
||||
if(PE_EnableLogging)
|
||||
Print("Blitz Play: WORST PERFORMER - '", strategyPerformances[worstIdx].strategyName,
|
||||
"' penalized! Lot size reduced from ", strategyPerformances[worstIdx].lotSizeBeforePenalty,
|
||||
" to minimum ", minLot, " (Score: ", DoubleToString(ranks[activeCount - 1].score, 2),
|
||||
", Profit: $", DoubleToString(strategyPerformances[worstIdx].quarterProfit, 2), ")");
|
||||
}
|
||||
}
|
||||
|
||||
// Log performance report
|
||||
if(PE_EnableLogging)
|
||||
{
|
||||
Print("=== Monthly Performance Ranking ===");
|
||||
for(int i = 0; i < activeCount; i++)
|
||||
{
|
||||
int strategyIdx = ranks[i].index;
|
||||
Print("Rank #", (i+1), ": ", strategyPerformances[strategyIdx].strategyName,
|
||||
" - Score: ", DoubleToString(ranks[i].score, 2),
|
||||
", Profit: $", DoubleToString(strategyPerformances[strategyIdx].quarterProfit, 2),
|
||||
", Win Rate: ", DoubleToString(strategyPerformances[strategyIdx].winRate, 2), "%",
|
||||
", Trades: ", (int)strategyPerformances[strategyIdx].quarterTrades,
|
||||
", Lot Size: ", DoubleToString(strategyPerformances[strategyIdx].currentLotSize, 2));
|
||||
}
|
||||
Print("===================================");
|
||||
}
|
||||
}
|
||||
|
||||
// Reset month metrics for all strategies
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].isActive)
|
||||
{
|
||||
strategyPerformances[i].quarterProfit = 0.0;
|
||||
strategyPerformances[i].quarterTrades = 0;
|
||||
strategyPerformances[i].quarterWins = 0;
|
||||
strategyPerformances[i].quarterLosses = 0;
|
||||
strategyPerformances[i].maxDrawdown = 0.0;
|
||||
strategyPerformances[i].winRate = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
// Update month dates
|
||||
MqlDateTime dt;
|
||||
TimeToStruct(now, dt);
|
||||
|
||||
// First day of current month
|
||||
dt.day = 1;
|
||||
dt.hour = 0;
|
||||
dt.min = 0;
|
||||
dt.sec = 0;
|
||||
currentMonthStart = StructToTime(dt);
|
||||
|
||||
// First day of next month - 1 second
|
||||
dt.mon += 1;
|
||||
if(dt.mon > 12)
|
||||
{
|
||||
dt.mon = 1;
|
||||
dt.year++;
|
||||
}
|
||||
currentMonthEnd = StructToTime(dt) - 1;
|
||||
|
||||
// Update month dates for all strategies
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
strategyPerformances[i].quarterStart = currentMonthStart;
|
||||
strategyPerformances[i].quarterEnd = currentMonthEnd;
|
||||
}
|
||||
|
||||
lastMonthCheck = now;
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get Current Lot Size for Strategy |
|
||||
//+------------------------------------------------------------------+
|
||||
double GetStrategyLotSize(string strategyName, int magicNumber)
|
||||
{
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].strategyName == strategyName &&
|
||||
strategyPerformances[i].magicNumber == magicNumber &&
|
||||
strategyPerformances[i].isActive)
|
||||
{
|
||||
return strategyPerformances[i].currentLotSize;
|
||||
}
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Process Performance Evaluation (call from OnTick) |
|
||||
//+------------------------------------------------------------------+
|
||||
void ProcessPerformanceEvaluation()
|
||||
{
|
||||
// Check if month ended
|
||||
CheckMonthEnd();
|
||||
|
||||
// Check for penalty expiration (blitz play)
|
||||
if(PE_EnableBlitzPlay)
|
||||
{
|
||||
datetime now = TimeCurrent();
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].isActive && strategyPerformances[i].inPenaltyMode)
|
||||
{
|
||||
// Check if penalty period has passed (one month = ~30 days)
|
||||
if(now - strategyPerformances[i].penaltyStartTime >= 2592000)
|
||||
{
|
||||
// Restore lot size to before penalty
|
||||
strategyPerformances[i].currentLotSize = strategyPerformances[i].lotSizeBeforePenalty;
|
||||
strategyPerformances[i].inPenaltyMode = false;
|
||||
strategyPerformances[i].penaltyStartTime = 0;
|
||||
|
||||
if(PE_EnableLogging)
|
||||
Print("Blitz Play: Penalty expired for '", strategyPerformances[i].strategyName,
|
||||
"'. Lot size restored to ", strategyPerformances[i].currentLotSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update performance metrics periodically (every hour)
|
||||
static datetime lastUpdate = 0;
|
||||
if(TimeCurrent() - lastUpdate >= 3600)
|
||||
{
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].isActive)
|
||||
{
|
||||
UpdateStrategyPerformance(strategyPerformances[i].strategyName,
|
||||
strategyPerformances[i].magicNumber);
|
||||
}
|
||||
}
|
||||
lastUpdate = TimeCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get Performance Summary |
|
||||
//+------------------------------------------------------------------+
|
||||
string GetPerformanceSummary()
|
||||
{
|
||||
string summary = "\n=== Performance Summary ===\n";
|
||||
summary += "Current Month: " + TimeToString(currentMonthStart) + " to " + TimeToString(currentMonthEnd) + "\n\n";
|
||||
|
||||
for(int i = 0; i < ArraySize(strategyPerformances); i++)
|
||||
{
|
||||
if(strategyPerformances[i].isActive)
|
||||
{
|
||||
summary += strategyPerformances[i].strategyName + ":\n";
|
||||
summary += " Profit: $" + DoubleToString(strategyPerformances[i].quarterProfit, 2) + "\n";
|
||||
summary += " Trades: " + IntegerToString((int)strategyPerformances[i].quarterTrades) + "\n";
|
||||
summary += " Win Rate: " + DoubleToString(strategyPerformances[i].winRate, 2) + "%\n";
|
||||
summary += " Lot Size: " + DoubleToString(strategyPerformances[i].currentLotSize, 2) + "\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
return summary;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,76 @@
|
||||
# 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")
|
||||
@@ -0,0 +1,300 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| DarvasBoxStrategy.mqh |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
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);
|
||||
dbData.volumeHandle = iVolumes(symbol, PERIOD_CURRENT, 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)
|
||||
{
|
||||
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()
|
||||
{
|
||||
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];
|
||||
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;
|
||||
|
||||
// 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(g_DB_LotSize, dbData.symbol, 0, sl, tp, "Darvas Box Breakout");
|
||||
else
|
||||
result = dbData.trade.Sell(g_DB_LotSize, 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_CURRENT, 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");
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,496 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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))
|
||||
{
|
||||
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))
|
||||
{
|
||||
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");
|
||||
Print("TRACE: Lot: ", g_ES_LotSize);
|
||||
|
||||
bool success = false;
|
||||
|
||||
if(order_type == ORDER_TYPE_BUY)
|
||||
{
|
||||
success = esData.trade.Buy(g_ES_LotSize, esData.symbol, 0, 0, 0, "EMA Crossover Trade");
|
||||
}
|
||||
else
|
||||
{
|
||||
success = esData.trade.Sell(g_ES_LotSize, 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);
|
||||
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;
|
||||
|
||||
double position_profit = PositionGetDouble(POSITION_PROFIT);
|
||||
double position_open_price = PositionGetDouble(POSITION_PRICE_OPEN);
|
||||
double current_price = PositionGetDouble(POSITION_PRICE_CURRENT);
|
||||
ENUM_POSITION_TYPE position_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
||||
|
||||
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;
|
||||
double trailing_stop_pips = ES_TrailingStop;
|
||||
|
||||
//--- Gleitender Stop (Trailing Stop) - nur wenn Position im Profit ist
|
||||
if(position_profit > 0) // Only apply trailing stop when in profit
|
||||
{
|
||||
if(position_type == POSITION_TYPE_BUY)
|
||||
{
|
||||
double new_stop_loss = current_price - (trailing_stop_pips * point * pips_multiplier);
|
||||
double current_stop_loss = PositionGetDouble(POSITION_SL);
|
||||
|
||||
// Only move stop loss if new stop is higher than current stop
|
||||
if(new_stop_loss > current_stop_loss)
|
||||
{
|
||||
ÄndereStopLoss(new_stop_loss);
|
||||
}
|
||||
}
|
||||
else if(position_type == POSITION_TYPE_SELL)
|
||||
{
|
||||
double new_stop_loss = current_price + (trailing_stop_pips * point * pips_multiplier);
|
||||
double current_stop_loss = PositionGetDouble(POSITION_SL);
|
||||
|
||||
// Only move stop loss if new stop is lower than current stop
|
||||
if(new_stop_loss < current_stop_loss || current_stop_loss == 0)
|
||||
{
|
||||
ÄndereStopLoss(new_stop_loss);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--- Ausstieg bei Preis unter/über EMA (Exit when price below/above EMA)
|
||||
if(ArraySize(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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
// Skip if not initialized (symbol not available)
|
||||
if(!esData.isInitialized)
|
||||
return;
|
||||
|
||||
esData.symbol = symbol; // Update symbol in case it changed
|
||||
|
||||
//--- Bar-Daten oder Tick-Daten verwenden (Use bar data or tick data)
|
||||
if(ES_UseBarData)
|
||||
{
|
||||
//--- Nur bei neuen Bars ausführen (Only execute on new bars)
|
||||
datetime current_bar_time = iTime(esData.symbol, ES_Timeframe, 0);
|
||||
|
||||
if(current_bar_time == esData.last_bar_time)
|
||||
{
|
||||
return; // Kein neuer Bar, nichts tun
|
||||
}
|
||||
|
||||
esData.last_bar_time = current_bar_time;
|
||||
}
|
||||
|
||||
//--- EMA Werte berechnen (Calculate EMA values)
|
||||
BerechneEMA();
|
||||
|
||||
//--- Debug: Aktuelle Werte ausgeben (Debug: Output current values)
|
||||
if(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];
|
||||
int digits = (int)SymbolInfoInteger(esData.symbol, SYMBOL_DIGITS);
|
||||
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("==================");
|
||||
}
|
||||
|
||||
//--- Überwachung prüfen (Check monitoring)
|
||||
if(esData.überwachung_aktiv)
|
||||
{
|
||||
if(ES_UseBarData)
|
||||
{
|
||||
// Bar-basierte Überwachungszeit
|
||||
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
|
||||
{
|
||||
// Tick-basierte Überwachungszeit
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--- Trigger-Bedingungen prüfen (Check trigger conditions)
|
||||
PrüfeTrigger();
|
||||
|
||||
//--- Trade Management (Trade management)
|
||||
VerwalteTrades();
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,240 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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]);
|
||||
}
|
||||
|
||||
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.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(!((currentHour < RC_tradingHourOneEnd && currentHour > RC_tradingHourOneBegin) ||
|
||||
(currentHour < RC_tradingHourTwoEnd && currentHour > RC_tradingHourTwoBegin)))
|
||||
{
|
||||
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;
|
||||
double closeCurr = iClose(Symbol(), Period(), 0);
|
||||
double priceToEmaDistance = (closeCurr - currentEMA) * 10;
|
||||
|
||||
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;
|
||||
bool isTrendStrong = MathAbs(emaSlope) > RC_emaSlopeThreshold || MathAbs(priceToEmaDistance) > 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;
|
||||
return;
|
||||
}
|
||||
|
||||
if(currentRSI < RC_overboughtLevel - RC_entryRSISellSpread && rcData.previousRSIDef >= RC_overboughtLevel &&
|
||||
!isSellPosition && !hasPosition && cooldownPassed)
|
||||
{
|
||||
rcData.trade.SetExpertMagicNumber(RC_MagicNumber);
|
||||
if(rcData.trade.Sell(g_RC_LotSize, rcData.symbol, 0.0, 0.0, 0.0, "Sell Order"))
|
||||
{
|
||||
rcData.lastTradeTime = currentTime;
|
||||
}
|
||||
}
|
||||
|
||||
if(currentRSI > RC_oversoldLevel + RC_entryRSIBuySpread && rcData.previousRSIDef <= RC_oversoldLevel &&
|
||||
!isBuyPosition && !hasPosition && cooldownPassed)
|
||||
{
|
||||
rcData.trade.SetExpertMagicNumber(RC_MagicNumber);
|
||||
if(rcData.trade.Buy(g_RC_LotSize, rcData.symbol, 0.0, 0.0, 0.0, "Buy Order"))
|
||||
{
|
||||
rcData.lastTradeTime = currentTime;
|
||||
}
|
||||
}
|
||||
|
||||
rcData.previousRSIDef = currentRSI;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,471 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| RSIMidPointHijackStrategy.mqh |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
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);
|
||||
rmData.trade.Sell(g_RM_LotSize, 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);
|
||||
rmData.trade.Buy(g_RM_LotSize, 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);
|
||||
rmData.trade.Sell(g_RM_LotSize, 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);
|
||||
rmData.trade.Buy(g_RM_LotSize, 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);
|
||||
rmData.trade.Buy(g_RM_LotSize, 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);
|
||||
rmData.trade.Sell(g_RM_LotSize, 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);
|
||||
rmData.trade.Buy(g_RM_LotSize, 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);
|
||||
rmData.trade.Sell(g_RM_LotSize, 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);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,493 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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)
|
||||
{
|
||||
// Check if market is open
|
||||
long tradeMode = SymbolInfoInteger(data.symbol, SYMBOL_TRADE_MODE);
|
||||
if(tradeMode != 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(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.SetTypeFilling(ORDER_FILLING_IOC);
|
||||
|
||||
// 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;
|
||||
|
||||
// Set trade parameters
|
||||
data.trade.SetDeviationInPoints(data.Slippage);
|
||||
data.trade.SetTypeFilling(ORDER_FILLING_IOC);
|
||||
data.trade.SetExpertMagicNumber(data.MagicNumber);
|
||||
|
||||
// Use dynamic lot size
|
||||
double tradeLotSize = lotSize > 0 ? lotSize : data.MaxLotSize;
|
||||
|
||||
// Place buy order using CTrade
|
||||
if(data.trade.Buy(tradeLotSize, 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;
|
||||
|
||||
// Set trade parameters
|
||||
data.trade.SetDeviationInPoints(data.Slippage);
|
||||
data.trade.SetTypeFilling(ORDER_FILLING_IOC);
|
||||
data.trade.SetExpertMagicNumber(data.MagicNumber);
|
||||
|
||||
// Use dynamic lot size
|
||||
double tradeLotSize = lotSize > 0 ? lotSize : data.MaxLotSize;
|
||||
|
||||
// Place sell order using CTrade
|
||||
if(data.trade.Sell(tradeLotSize, data.symbol, currentBid, sl, tp, "RSI Overbought Crossover Sell"))
|
||||
{
|
||||
data.isPositionOpen = true;
|
||||
data.positionOpenPrice = currentBid;
|
||||
data.positionOpenTime = TimeCurrent();
|
||||
data.lastPositionType = POSITION_TYPE_SELL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,451 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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;
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
double minLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
|
||||
double maxLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
|
||||
double lotStep = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
|
||||
|
||||
// Round to lot step
|
||||
if(lotStep > 0)
|
||||
lotSize = MathFloor(lotSize / lotStep) * lotStep;
|
||||
|
||||
// Apply min/max constraints
|
||||
if(lotSize < minLot)
|
||||
lotSize = minLot;
|
||||
if(lotSize > maxLot)
|
||||
lotSize = maxLot;
|
||||
|
||||
return 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)
|
||||
{
|
||||
// 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;
|
||||
|
||||
datetime current_bar_time = iTime(data.symbol, TimeFrame, 0);
|
||||
if(current_bar_time == data.last_bar_time)
|
||||
return;
|
||||
|
||||
data.last_bar_time = current_bar_time;
|
||||
|
||||
if(!UpdateRSI(data))
|
||||
return;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,736 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| UnitedEA.mq5 |
|
||||
//| Cent ".c" symbols; InpDynamicRefDeposit MUST match ACCOUNT_ |
|
||||
//| CURRENCY numbers (USC ~50k for ~$500, or USD ~500 — not mixed). |
|
||||
//| Per-order max lots = broker spec 最大量 SYMBOL_VOLUME_MAX |
|
||||
//| (often 1000 on *.c); EA cannot exceed it — see symbol contract. |
|
||||
//| Copyright 2025, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2025, MetaQuotes Ltd."
|
||||
#property link "https://www.mql5.com"
|
||||
#property version "1.10"
|
||||
#property strict
|
||||
|
||||
#include <Trade\Trade.mqh>
|
||||
#include <Trade\PositionInfo.mqh>
|
||||
#include <Indicators\Trend.mqh>
|
||||
#include <Indicators\Volumes.mqh>
|
||||
#include "MagicNumberHelpers.mqh"
|
||||
|
||||
// Lot globals must exist before strategy .mqh (Darvas uses g_DB_LotSize; EMA/RC/RM use g_ES/g_RC/g_RM)
|
||||
double g_ES_LotSize;
|
||||
double g_RC_LotSize;
|
||||
double g_RM_LotSize;
|
||||
double g_DB_LotSize;
|
||||
double g_DynLotScaleLast = 1.0; // last applied scale: lots = baseLot * scale * InpLotSizeScale
|
||||
double g_DynamicRefBaseline = 0.0; // when InpDynamicRefDeposit<=0, frozen ref = equity at first sizing call
|
||||
|
||||
// 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/RSIReversalAsianStrategy.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 EnableRSIScalpingNVDA = true;
|
||||
input bool EnableRSIScalpingTSLA = true;
|
||||
input bool EnableRSIScalpingXAUUSD = true;
|
||||
input bool EnableRSIReversalAsianEURUSD = true;
|
||||
input bool EnableRSIReversalAsianAUDUSD = true;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Dynamic lot sizing — 默认「按比例」:lots = base × (equity/ref) × lotScale |
|
||||
//| 可选幂曲线:lots = base × (equity/ref)^exp × lotScale(旧行为) |
|
||||
//| min/max 约束的是「比例系数」不是手数本身;max<=0 表示比例系数上不封顶 |
|
||||
//| |
|
||||
//| USC (deposit currency) vs "lot size": |
|
||||
//| • Equity/ref for the multiplier are BOTH in account currency |
|
||||
//| (USC). Same units → ratio is correct; no ×100 on the ratio. |
|
||||
//| • Strategy base lots (e.g. DB_BaseLotSize) are ORDER VOLUME in |
|
||||
//| lots, not "USC lots". Broker SYMBOL_VOLUME_* / contract define |
|
||||
//| how much margin and P/L appear in USC. |
|
||||
//| • Do not multiply lot inputs by 100 only because balance is USC. |
|
||||
//| If DD too high: raise InpDynamicRefDeposit and/or lower base lots.|
|
||||
//| If balance is USD ~500 but ref is ~50k–300k: mult→floor, lots→0.01.|
|
||||
//| Ref<=0: 挂上时余额/净值为参考,之后手数随净值相对该基准的比例变化。 |
|
||||
//| 单笔上限:品种规格里的「最大量」(SYMBOL_VOLUME_MAX),非 EA 参数。 |
|
||||
//| InpMaxLotsPerOrder:EA 再截一刀,防止动态+scale 顶满 1000 爆仓。 |
|
||||
//+------------------------------------------------------------------+
|
||||
enum ENUM_LOT_SCALE_CURVE
|
||||
{
|
||||
LOT_CURVE_PROPORTIONAL = 0, // 按比例:scale = 净值/参考(线性)
|
||||
LOT_CURVE_POWER = 1 // 幂:scale = (净值/参考)^exp
|
||||
};
|
||||
|
||||
input group "=== Dynamic lot sizing (动态手数) ==="
|
||||
input bool InpDynamicLotEnable = true; // Enable balance/equity-based scaling
|
||||
input ENUM_LOT_SCALE_CURVE InpDynamicLotCurve = LOT_CURVE_PROPORTIONAL; // 默认按比例;幂曲线=旧 (equity/ref)^exp
|
||||
input double InpDynamicRefDeposit = 0.0; // <=0: auto — ref=挂上时净值/余额(与测试器初始一致则手数随盈利涨); >0 手动参考金
|
||||
input bool InpDynamicRefEqualsEquity = false; // true: 比例系数固定为 1(只用基础手×lotScale)
|
||||
input double InpDynamicExponent = 1.22; // 仅 LOT_CURVE_POWER 时:(净值/参考) 的指数
|
||||
input double InpDynamicMinMult = 0.0; // 比例系数下限;<=0 不抬(按比例时净值<参考会缩小手数)
|
||||
input double InpDynamicMaxMult = 20.0; // 比例系数上限;<=0 不封顶(高风险)
|
||||
input bool InpDynamicUseEquity = true; // true=ACCOUNT_EQUITY, false=ACCOUNT_BALANCE
|
||||
input double InpDynamicStockLotCap = 0.0; // Max lots after scale (0=off); raise if InpLotSizeScale is large
|
||||
input double InpLotSizeScale = 1.0; // 全局手数倍率; 曾用100易过大,默认1按需再加
|
||||
input double InpMaxLotsPerOrder = 20.0; // 单笔最大手数(0=仅券商SYMBOL_VOLUME_MAX); 保守可设5~10
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Strategy 1: DarvasBoxXAUUSD (cent symbol) |
|
||||
//+------------------------------------------------------------------+
|
||||
input group "=== DarvasBox Strategy ==="
|
||||
input string DB_Symbol = "XAUUSD.c";
|
||||
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;
|
||||
input double DB_BaseLotSize = 0.02; // Base lot at InpDynamicRefDeposit (Darvas)
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Strategy 2: EMASlopeDistanceCocktailXAUUSD |
|
||||
//| Cent: gold is usually "XAUUSD.c" (verify in Market Watch). |
|
||||
//+------------------------------------------------------------------+
|
||||
input group "=== EMA Slope Distance Strategy ==="
|
||||
input string ES_Symbol = "XAUUSD.c";
|
||||
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 = 250.0;
|
||||
input double ES_LotGröße = 0.05;
|
||||
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;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Strategy 3: RSICrossOverReversalXAUUSD |
|
||||
//| Cent: use "XAUUSD.c" if that is what the broker lists. |
|
||||
//+------------------------------------------------------------------+
|
||||
input group "=== RSI CrossOver Reversal Strategy ==="
|
||||
input string RC_Symbol = "XAUUSD.c";
|
||||
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.02;
|
||||
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 |
|
||||
//| Cent: use "XAUUSD.c" if that is what the broker lists. |
|
||||
//+------------------------------------------------------------------+
|
||||
input group "=== RSI MidPoint Hijack Strategy ==="
|
||||
input string RM_Symbol = "XAUUSD.c";
|
||||
input ENUM_TIMEFRAMES RM_InpTimeframe = PERIOD_H1;
|
||||
input double RM_InpLotSize = 0.03;
|
||||
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 |
|
||||
//| |
|
||||
//| USC cent: many symbols end with ".c" — use Market Watch names. |
|
||||
//| Stocks may be "AAPL.US.c" or unchanged; verify before live. |
|
||||
//+------------------------------------------------------------------+
|
||||
input group "=== RSI Scalping APPL (AAPL) - cent ==="
|
||||
input string RS_APPL_Symbol = "AAPL.US.c"; // If missing, try AAPL.US / NASDAQ:AAPL / 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 = 38;
|
||||
input int RS_APPL_MagicNumber = 20001;
|
||||
input int RS_APPL_Slippage = 3;
|
||||
|
||||
input group "=== RSI Scalping BTCUSD ==="
|
||||
input string RS_BTCUSD_Symbol = "BTCUSD.c"; // If missing, try BTCUSD or BTC/USD
|
||||
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.15;
|
||||
input int RS_BTCUSD_MagicNumber = 123459123;
|
||||
input int RS_BTCUSD_Slippage = 3;
|
||||
|
||||
input group "=== RSI Scalping NVDA - cent ==="
|
||||
input string RS_NVDA_Symbol = "NVDA.US.c"; // If missing, try NVDA.US / NASDAQ:NVDA / 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 = 75;
|
||||
input int RS_NVDA_MagicNumber = 20003;
|
||||
input int RS_NVDA_Slippage = 3;
|
||||
|
||||
input group "=== RSI Scalping TSLA - cent ==="
|
||||
input string RS_TSLA_Symbol = "TSLA.US.c"; // If missing, try TSLA.US / NASDAQ:TSLA / 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 = 75;
|
||||
input int RS_TSLA_MagicNumber = 125421321;
|
||||
input int RS_TSLA_Slippage = 3;
|
||||
|
||||
input group "=== RSI Scalping XAUUSD ==="
|
||||
input string RS_XAUUSD_Symbol = "XAUUSD.c";
|
||||
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.15;
|
||||
input int RS_XAUUSD_MagicNumber = 129102315;
|
||||
input int RS_XAUUSD_Slippage = 3;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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.c";
|
||||
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.15;
|
||||
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.c";
|
||||
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.3;
|
||||
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;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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;
|
||||
};
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Global Variables - RSI Reversal Asian |
|
||||
//+------------------------------------------------------------------+
|
||||
RSIReversalAsianData rraEURUSDData;
|
||||
RSIReversalAsianData rraAUDUSDData;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Dynamic lot helpers |
|
||||
//+------------------------------------------------------------------+
|
||||
double DynClamp(const double v, const double lo, const double hi)
|
||||
{
|
||||
return MathMax(lo, MathMin(hi, v));
|
||||
}
|
||||
|
||||
// Clamp scale factor (proportion or pow result). max<=0 = no upper clamp.
|
||||
double ApplyDynamicScaleClamp(const double scaleRaw)
|
||||
{
|
||||
double s = scaleRaw;
|
||||
if(InpDynamicMinMult > 0.0)
|
||||
s = MathMax(s, InpDynamicMinMult);
|
||||
if(InpDynamicMaxMult > 0.0)
|
||||
s = MathMin(s, InpDynamicMaxMult);
|
||||
return s;
|
||||
}
|
||||
|
||||
// Reference for (equity/ref)^exp: manual deposit, or first-seen balance when input <= 0
|
||||
double GetDynamicRefForRatio()
|
||||
{
|
||||
if(InpDynamicRefDeposit > 0.0)
|
||||
return MathMax(InpDynamicRefDeposit, 1.0);
|
||||
double capNow = InpDynamicUseEquity ? AccountInfoDouble(ACCOUNT_EQUITY) : AccountInfoDouble(ACCOUNT_BALANCE);
|
||||
if(g_DynamicRefBaseline <= 0.0)
|
||||
g_DynamicRefBaseline = MathMax(capNow, 1.0);
|
||||
return MathMax(g_DynamicRefBaseline, 1.0);
|
||||
}
|
||||
|
||||
// Broker hard cap: 最大量 = SYMBOL_VOLUME_MAX (e.g. 1000 on EURUSD.c / XAUUSD.c)
|
||||
double NormalizeVolumeForSymbol(const string symbol, double lots)
|
||||
{
|
||||
double minL = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
|
||||
double maxL = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
|
||||
double step = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
|
||||
if(step > 0.0)
|
||||
lots = MathFloor(lots / step + 1e-12) * step;
|
||||
if(lots < minL) lots = minL;
|
||||
if(lots > maxL) lots = maxL;
|
||||
return lots;
|
||||
}
|
||||
|
||||
// Apply EA risk cap before broker min/step/max (InpMaxLotsPerOrder 0 = disabled)
|
||||
double NormalizeVolumeForSymbolWithEACap(const string symbol, double lots)
|
||||
{
|
||||
if(InpMaxLotsPerOrder > 0.0)
|
||||
lots = MathMin(lots, InpMaxLotsPerOrder);
|
||||
return NormalizeVolumeForSymbol(symbol, lots);
|
||||
}
|
||||
|
||||
// Scale factor for lots: baseLot * scale * InpLotSizeScale (then caps)
|
||||
double GetDynamicLotScaleFactor()
|
||||
{
|
||||
if(!InpDynamicLotEnable)
|
||||
return 1.0;
|
||||
if(InpDynamicRefEqualsEquity)
|
||||
return ApplyDynamicScaleClamp(1.0);
|
||||
double cap = InpDynamicUseEquity ? AccountInfoDouble(ACCOUNT_EQUITY) : AccountInfoDouble(ACCOUNT_BALANCE);
|
||||
double refv = GetDynamicRefForRatio();
|
||||
if(cap <= 0.0)
|
||||
cap = refv;
|
||||
double ratio = cap / refv;
|
||||
if(ratio <= 0.0)
|
||||
ratio = 1.0;
|
||||
double scaleRaw = ratio;
|
||||
if(InpDynamicLotCurve == LOT_CURVE_POWER)
|
||||
scaleRaw = MathPow(ratio, InpDynamicExponent);
|
||||
return ApplyDynamicScaleClamp(scaleRaw);
|
||||
}
|
||||
|
||||
// baseLot = size at reference deposit; optionalCap 0 = no extra ceiling (broker min/max still apply)
|
||||
double DynamicLotForSymbol(const string symbol, const double baseLot, const double optionalCap = 0.0)
|
||||
{
|
||||
double scale = GetDynamicLotScaleFactor();
|
||||
g_DynLotScaleLast = scale;
|
||||
double sc = (InpLotSizeScale > 0.0 ? InpLotSizeScale : 1.0);
|
||||
double v = baseLot * scale * sc;
|
||||
if(optionalCap > 0.0 && v > optionalCap)
|
||||
v = optionalCap;
|
||||
return NormalizeVolumeForSymbolWithEACap(symbol, v);
|
||||
}
|
||||
|
||||
void RefreshDynamicStrategyLots()
|
||||
{
|
||||
double sc = (InpLotSizeScale > 0.0 ? InpLotSizeScale : 1.0);
|
||||
if(!InpDynamicLotEnable)
|
||||
{
|
||||
g_ES_LotSize = NormalizeVolumeForSymbolWithEACap(ES_Symbol, ES_LotGröße * sc);
|
||||
g_RC_LotSize = NormalizeVolumeForSymbolWithEACap(RC_Symbol, RC_lotSize * sc);
|
||||
g_RM_LotSize = NormalizeVolumeForSymbolWithEACap(RM_Symbol, RM_InpLotSize * sc);
|
||||
g_DB_LotSize = NormalizeVolumeForSymbolWithEACap(DB_Symbol, DB_BaseLotSize * sc);
|
||||
g_DynLotScaleLast = 1.0;
|
||||
return;
|
||||
}
|
||||
g_ES_LotSize = DynamicLotForSymbol(ES_Symbol, ES_LotGröße);
|
||||
g_RC_LotSize = DynamicLotForSymbol(RC_Symbol, RC_lotSize);
|
||||
g_RM_LotSize = DynamicLotForSymbol(RM_Symbol, RM_InpLotSize);
|
||||
g_DB_LotSize = DynamicLotForSymbol(DB_Symbol, DB_BaseLotSize);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Expert initialization function |
|
||||
//+------------------------------------------------------------------+
|
||||
int OnInit()
|
||||
{
|
||||
int initResult = INIT_SUCCEEDED;
|
||||
|
||||
g_DynamicRefBaseline = 0.0;
|
||||
|
||||
RefreshDynamicStrategyLots();
|
||||
|
||||
string acctCur = AccountInfoString(ACCOUNT_CURRENCY);
|
||||
double eq0 = AccountInfoDouble(ACCOUNT_EQUITY);
|
||||
if(InpDynamicLotEnable && !InpDynamicRefEqualsEquity && InpDynamicRefDeposit > 1000.0 && eq0 > 0.0
|
||||
&& eq0 <= InpDynamicRefDeposit / 25.0)
|
||||
Print("United EA: equity ", DoubleToString(eq0, 2), " ", acctCur, " vs ref ", InpDynamicRefDeposit,
|
||||
" — dynamic mult is tiny; set InpDynamicRefDeposit to your balance in ", acctCur,
|
||||
" (e.g. 500 for USD) or enable InpDynamicRefEqualsEquity. Else lots stay at broker minimum.");
|
||||
|
||||
// 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);
|
||||
|
||||
// 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, RRA_EURUSD_MaxLotSize,
|
||||
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, RRA_AUDUSD_MaxLotSize,
|
||||
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, "'");
|
||||
|
||||
double refEffInit = GetDynamicRefForRatio();
|
||||
double capInit = InpDynamicUseEquity ? eq0 : AccountInfoDouble(ACCOUNT_BALANCE);
|
||||
if(capInit <= 0.0)
|
||||
capInit = refEffInit;
|
||||
double ratioInit = capInit / refEffInit;
|
||||
double powInit = MathPow(ratioInit, InpDynamicExponent);
|
||||
string curveStr = (InpDynamicLotCurve == LOT_CURVE_POWER ? "POWER" : "PROP");
|
||||
Print("United EA v1.10 ", acctCur, " curve=", curveStr, " equity=", DoubleToString(eq0, 2), " refEff=", DoubleToString(refEffInit, 2),
|
||||
" (inpRef=", InpDynamicRefDeposit, " baseline=", DoubleToString(g_DynamicRefBaseline, 2), ") equity/ref=", DoubleToString(ratioInit, 6),
|
||||
" pow^exp=", DoubleToString(powInit, 6), " scaleOut=", DoubleToString(g_DynLotScaleLast, 6),
|
||||
" minS=", InpDynamicMinMult, " maxS=", InpDynamicMaxMult, " lotScale=", InpLotSizeScale, " maxLots=", InpMaxLotsPerOrder,
|
||||
" lots ES=", g_ES_LotSize, " RC=", g_RC_LotSize, " RM=", g_RM_LotSize, " DB=", g_DB_LotSize);
|
||||
Print("United EA initialized. Active strategies: ",
|
||||
(EnableDarvasBox ? "DarvasBox " : ""),
|
||||
(EnableEMASlopeDistance ? "EMASlope " : ""),
|
||||
(EnableRSICrossOverReversal ? "RSICrossOver " : ""),
|
||||
(EnableRSIMidPointHijack ? "RSIMidPoint " : ""),
|
||||
(EnableRSIScalpingAPPL ? "RSIScalpingAPPL " : ""),
|
||||
(EnableRSIScalpingBTCUSD ? "RSIScalpingBTCUSD " : ""),
|
||||
(EnableRSIScalpingNVDA ? "RSIScalpingNVDA " : ""),
|
||||
(EnableRSIScalpingTSLA ? "RSIScalpingTSLA " : ""),
|
||||
(EnableRSIScalpingXAUUSD ? "RSIScalpingXAUUSD " : ""),
|
||||
(EnableRSIReversalAsianEURUSD ? "RSIReversalAsianEURUSD " : ""),
|
||||
(EnableRSIReversalAsianAUDUSD ? "RSIReversalAsianAUDUSD " : ""));
|
||||
|
||||
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(EnableRSIReversalAsianEURUSD)
|
||||
DeinitRSIReversalAsian(rraEURUSDData);
|
||||
|
||||
if(EnableRSIReversalAsianAUDUSD)
|
||||
DeinitRSIReversalAsian(rraAUDUSDData);
|
||||
|
||||
Print("United EA deinitialized. Reason: ", reason);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Expert tick function |
|
||||
//+------------------------------------------------------------------+
|
||||
void OnTick()
|
||||
{
|
||||
RefreshDynamicStrategyLots();
|
||||
|
||||
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,
|
||||
DynamicLotForSymbol(RS_APPL_Symbol, RS_APPL_LotSize, InpDynamicStockLotCap),
|
||||
RS_APPL_MagicNumber);
|
||||
|
||||
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, DynamicLotForSymbol(RS_BTCUSD_Symbol, RS_BTCUSD_LotSize), RS_BTCUSD_MagicNumber);
|
||||
|
||||
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,
|
||||
DynamicLotForSymbol(RS_NVDA_Symbol, RS_NVDA_LotSize, InpDynamicStockLotCap),
|
||||
RS_NVDA_MagicNumber);
|
||||
|
||||
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,
|
||||
DynamicLotForSymbol(RS_TSLA_Symbol, RS_TSLA_LotSize, InpDynamicStockLotCap),
|
||||
RS_TSLA_MagicNumber);
|
||||
|
||||
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, DynamicLotForSymbol(RS_XAUUSD_Symbol, RS_XAUUSD_LotSize), RS_XAUUSD_MagicNumber);
|
||||
|
||||
if(EnableRSIReversalAsianEURUSD)
|
||||
ProcessRSIReversalAsian(rraEURUSDData, DynamicLotForSymbol(RRA_EURUSD_Symbol, RRA_EURUSD_MaxLotSize));
|
||||
|
||||
if(EnableRSIReversalAsianAUDUSD)
|
||||
ProcessRSIReversalAsian(rraAUDUSDData, DynamicLotForSymbol(RRA_AUDUSD_Symbol, RRA_AUDUSD_MaxLotSize));
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
@@ -0,0 +1,641 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| UnitedEA.mq5 |
|
||||
//| Copyright 2025, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2025, MetaQuotes Ltd."
|
||||
#property link "https://www.mql5.com"
|
||||
#property version "1.00"
|
||||
#property strict
|
||||
|
||||
#include <Trade\Trade.mqh>
|
||||
#include <Trade\PositionInfo.mqh>
|
||||
#include <Indicators\Trend.mqh>
|
||||
#include <Indicators\Volumes.mqh>
|
||||
#include "MagicNumberHelpers.mqh"
|
||||
#include "PerformanceEvaluator.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 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 = 250.0;
|
||||
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;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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 |
|
||||
//| - 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 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;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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;
|
||||
};
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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 rsNVDAData;
|
||||
RSIScalpingData rsTSLAData;
|
||||
RSIScalpingData rsXAUUSDData;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Global Variables for Dynamic Lot Sizes |
|
||||
//+------------------------------------------------------------------+
|
||||
// All strategies start with minimum lot size for safety (will be adjusted by performance evaluator)
|
||||
double g_DB_LotSize = 0.01; // DarvasBox uses fixed lot size
|
||||
double g_ES_LotSize = 0.01; // EMA Slope Distance - start with minimum
|
||||
double g_RC_LotSize = 0.01; // RSI CrossOver Reversal - start with minimum
|
||||
double g_RM_LotSize = 0.01; // RSI MidPoint Hijack - start with minimum
|
||||
double g_RS_APPL_LotSize = 5.0; // Stock - start with stock minimum (5.0)
|
||||
double g_RS_BTCUSD_LotSize = 0.01; // Crypto - start with forex minimum (0.01)
|
||||
double g_RS_NVDA_LotSize = 5.0; // Stock - start with stock minimum (5.0)
|
||||
double g_RS_TSLA_LotSize = 5.0; // Stock - start with stock minimum (5.0)
|
||||
double g_RS_XAUUSD_LotSize = 0.01; // Forex - start with forex minimum (0.01)
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Expert initialization function |
|
||||
//+------------------------------------------------------------------+
|
||||
int OnInit()
|
||||
{
|
||||
int initResult = INIT_SUCCEEDED;
|
||||
|
||||
// Initialize Performance Evaluator
|
||||
InitPerformanceTracking();
|
||||
|
||||
// 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, "'");
|
||||
else
|
||||
RegisterStrategy("DarvasBox", DB_MagicNumber, 0.01, DB_Symbol); // Fixed lot size
|
||||
}
|
||||
|
||||
if(EnableEMASlopeDistance)
|
||||
{
|
||||
if(!InitEMASlopeDistance(ES_Symbol))
|
||||
Print("Warning: EMASlopeDistance strategy failed to initialize for symbol '", ES_Symbol, "'");
|
||||
else
|
||||
{
|
||||
RegisterStrategy("EMASlopeDistance", ES_MagicNumber, ES_LotGröße, ES_Symbol);
|
||||
// Start with minimum lot size (will be adjusted by performance evaluator)
|
||||
double minLot = GetMinLotSizeForSymbol(ES_Symbol);
|
||||
g_ES_LotSize = minLot;
|
||||
}
|
||||
}
|
||||
|
||||
if(EnableRSICrossOverReversal)
|
||||
{
|
||||
if(!InitRSICrossOverReversal(RC_Symbol))
|
||||
Print("Warning: RSICrossOverReversal strategy failed to initialize for symbol '", RC_Symbol, "'");
|
||||
else
|
||||
{
|
||||
RegisterStrategy("RSICrossOverReversal", RC_MagicNumber, RC_lotSize, RC_Symbol);
|
||||
// Start with minimum lot size (will be adjusted by performance evaluator)
|
||||
double minLot = GetMinLotSizeForSymbol(RC_Symbol);
|
||||
g_RC_LotSize = minLot;
|
||||
}
|
||||
}
|
||||
|
||||
if(EnableRSIMidPointHijack)
|
||||
{
|
||||
if(!InitRSIMidPointHijack(RM_Symbol))
|
||||
Print("Warning: RSIMidPointHijack strategy failed to initialize for symbol '", RM_Symbol, "'");
|
||||
else
|
||||
{
|
||||
RegisterStrategy("RSIMidPointHijack", RM_InpMagicNumberRSIFollow, RM_InpLotSize, RM_Symbol);
|
||||
RegisterStrategy("RSIMidPointHijack_Reverse", RM_InpMagicNumberRSIReverse, RM_InpLotSize, RM_Symbol);
|
||||
RegisterStrategy("RSIMidPointHijack_EMACross", RM_InpMagicNumberEMACross, RM_InpLotSize, RM_Symbol);
|
||||
// Start with minimum lot size (will be adjusted by performance evaluator)
|
||||
double minLot = GetMinLotSizeForSymbol(RM_Symbol);
|
||||
g_RM_LotSize = minLot;
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
RegisterStrategy("RSIScalpingAPPL", RS_APPL_MagicNumber, RS_APPL_LotSize, RS_APPL_Symbol);
|
||||
// Start with minimum lot size (will be adjusted by performance evaluator)
|
||||
double minLot = GetMinLotSizeForSymbol(RS_APPL_Symbol);
|
||||
g_RS_APPL_LotSize = minLot;
|
||||
}
|
||||
|
||||
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);
|
||||
RegisterStrategy("RSIScalpingBTCUSD", RS_BTCUSD_MagicNumber, RS_BTCUSD_LotSize, RS_BTCUSD_Symbol);
|
||||
// Start with minimum lot size (will be adjusted by performance evaluator)
|
||||
double minLot = GetMinLotSizeForSymbol(RS_BTCUSD_Symbol);
|
||||
g_RS_BTCUSD_LotSize = minLot;
|
||||
}
|
||||
|
||||
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);
|
||||
RegisterStrategy("RSIScalpingNVDA", RS_NVDA_MagicNumber, RS_NVDA_LotSize, RS_NVDA_Symbol);
|
||||
// Start with minimum lot size (will be adjusted by performance evaluator)
|
||||
double minLot = GetMinLotSizeForSymbol(RS_NVDA_Symbol);
|
||||
g_RS_NVDA_LotSize = minLot;
|
||||
}
|
||||
|
||||
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);
|
||||
RegisterStrategy("RSIScalpingTSLA", RS_TSLA_MagicNumber, RS_TSLA_LotSize, RS_TSLA_Symbol);
|
||||
// Start with minimum lot size (will be adjusted by performance evaluator)
|
||||
double minLot = GetMinLotSizeForSymbol(RS_TSLA_Symbol);
|
||||
g_RS_TSLA_LotSize = minLot;
|
||||
}
|
||||
|
||||
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);
|
||||
RegisterStrategy("RSIScalpingXAUUSD", RS_XAUUSD_MagicNumber, RS_XAUUSD_LotSize, RS_XAUUSD_Symbol);
|
||||
// Start with minimum lot size (will be adjusted by performance evaluator)
|
||||
double minLot = GetMinLotSizeForSymbol(RS_XAUUSD_Symbol);
|
||||
g_RS_XAUUSD_LotSize = minLot;
|
||||
}
|
||||
|
||||
// Load adjusted lot sizes from performance evaluator
|
||||
if(PE_EnableAutoAdjustment)
|
||||
{
|
||||
double adjustedLot;
|
||||
adjustedLot = GetStrategyLotSize("EMASlopeDistance", ES_MagicNumber);
|
||||
if(adjustedLot > 0) g_ES_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSICrossOverReversal", RC_MagicNumber);
|
||||
if(adjustedLot > 0) g_RC_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIMidPointHijack", RM_InpMagicNumberRSIFollow);
|
||||
if(adjustedLot > 0) g_RM_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIScalpingAPPL", RS_APPL_MagicNumber);
|
||||
if(adjustedLot > 0) g_RS_APPL_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIScalpingBTCUSD", RS_BTCUSD_MagicNumber);
|
||||
if(adjustedLot > 0) g_RS_BTCUSD_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIScalpingNVDA", RS_NVDA_MagicNumber);
|
||||
if(adjustedLot > 0) g_RS_NVDA_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIScalpingTSLA", RS_TSLA_MagicNumber);
|
||||
if(adjustedLot > 0) g_RS_TSLA_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIScalpingXAUUSD", RS_XAUUSD_MagicNumber);
|
||||
if(adjustedLot > 0) g_RS_XAUUSD_LotSize = adjustedLot;
|
||||
}
|
||||
|
||||
Print("United EA initialized. Active strategies: ",
|
||||
(EnableDarvasBox ? "DarvasBox " : ""),
|
||||
(EnableEMASlopeDistance ? "EMASlope " : ""),
|
||||
(EnableRSICrossOverReversal ? "RSICrossOver " : ""),
|
||||
(EnableRSIMidPointHijack ? "RSIMidPoint " : ""),
|
||||
(EnableRSIScalpingAPPL ? "RSIScalpingAPPL " : ""),
|
||||
(EnableRSIScalpingBTCUSD ? "RSIScalpingBTCUSD " : ""),
|
||||
(EnableRSIScalpingNVDA ? "RSIScalpingNVDA " : ""),
|
||||
(EnableRSIScalpingTSLA ? "RSIScalpingTSLA " : ""),
|
||||
(EnableRSIScalpingXAUUSD ? "RSIScalpingXAUUSD " : ""));
|
||||
|
||||
if(PE_EnableLogging)
|
||||
Print(GetPerformanceSummary());
|
||||
|
||||
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);
|
||||
|
||||
Print("United EA deinitialized. Reason: ", reason);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Expert tick function |
|
||||
//+------------------------------------------------------------------+
|
||||
void OnTick()
|
||||
{
|
||||
// Process performance evaluation (checks for quarter end and adjusts lot sizes)
|
||||
ProcessPerformanceEvaluation();
|
||||
|
||||
// Update lot sizes from performance evaluator if auto-adjustment is enabled
|
||||
if(PE_EnableAutoAdjustment)
|
||||
{
|
||||
double adjustedLot;
|
||||
adjustedLot = GetStrategyLotSize("EMASlopeDistance", ES_MagicNumber);
|
||||
if(adjustedLot > 0) g_ES_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSICrossOverReversal", RC_MagicNumber);
|
||||
if(adjustedLot > 0) g_RC_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIMidPointHijack", RM_InpMagicNumberRSIFollow);
|
||||
if(adjustedLot > 0) g_RM_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIScalpingAPPL", RS_APPL_MagicNumber);
|
||||
if(adjustedLot > 0) g_RS_APPL_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIScalpingBTCUSD", RS_BTCUSD_MagicNumber);
|
||||
if(adjustedLot > 0) g_RS_BTCUSD_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIScalpingNVDA", RS_NVDA_MagicNumber);
|
||||
if(adjustedLot > 0) g_RS_NVDA_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIScalpingTSLA", RS_TSLA_MagicNumber);
|
||||
if(adjustedLot > 0) g_RS_TSLA_LotSize = adjustedLot;
|
||||
|
||||
adjustedLot = GetStrategyLotSize("RSIScalpingXAUUSD", RS_XAUUSD_MagicNumber);
|
||||
if(adjustedLot > 0) g_RS_XAUUSD_LotSize = adjustedLot;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Include strategy implementations |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "Strategies/DarvasBoxStrategy.mqh"
|
||||
#include "Strategies/EMASlopeDistanceStrategy.mqh"
|
||||
#include "Strategies/RSICrossOverReversalStrategy.mqh"
|
||||
#include "Strategies/RSIMidPointHijackStrategy.mqh"
|
||||
#include "Strategies/RSIScalpingStrategy.mqh"
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
Reference in New Issue
Block a user