@@ -1,426 +0,0 @@
|
|||||||
//+------------------------------------------------------------------+
|
|
||||||
//| ScoringTrade.mq5 |
|
|
||||||
//| Generated by ChatGPT |
|
|
||||||
//| |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
#property strict
|
|
||||||
#include <Trade\Trade.mqh>
|
|
||||||
|
|
||||||
// Input parameters
|
|
||||||
input int MagicNumber = 42; // Unique identifier for this EA's trades
|
|
||||||
input int scoreThreshold = 15000; // Minimum score required to enter a trade (increased for BTC's larger price movements)
|
|
||||||
input int slopeThreshold = 3500; // Minimum EMA slope value to consider trend significant (increased for BTC's steeper trends)
|
|
||||||
input double maxScore = 25000; // Maximum allowed score before clamping (prevents excessive trade signals)
|
|
||||||
input int cooldownMinutes = 18; // Minimum time between crossover signals (prevents over-trading)
|
|
||||||
input int tradeCooldownMinutes = 44; // Minimum time between consecutive trades (trade debounce period)
|
|
||||||
input ENUM_TIMEFRAMES emaTimeFrame = PERIOD_H1; // Timeframe for EMA calculation (1-hour candles)
|
|
||||||
input double delayClampAbsolute = 5000; // Score threshold for applying decay (prevents score from growing too large)
|
|
||||||
input int emaPeriod = 139; // Number of periods for EMA calculation (longer period for smoother trend)
|
|
||||||
input double crossOverStep = 2500; // Score adjustment when price crosses EMA (increased for BTC's larger moves)
|
|
||||||
input double slopeThresholdStep = 2000; // Score adjustment for significant slope changes (increased for BTC)
|
|
||||||
input double emaDistanceStep = 500; // Score adjustment for price distance from EMA (increased for BTC)
|
|
||||||
input double emaDecayStep = 0; // Score decay rate when no significant signals (0 means no decay)
|
|
||||||
input double decayMultiplier = 0.08; // Multiplier applied to score when above delayClampAbsolute
|
|
||||||
input double distanceThreshold = 7100; // Minimum price-EMA distance to trigger score adjustment (increased for BTC)
|
|
||||||
input double atrMultiplier = 3.9; // Multiplier for dynamic stop loss calculation based on ATR
|
|
||||||
input double TrailingStop = 10; // Distance in points for trailing stop loss
|
|
||||||
input bool ApplyTrailingStop = true; // Enable/disable trailing stop functionality
|
|
||||||
input int maxCrossoverTrades = 14; // Maximum number of trades allowed per crossover signal
|
|
||||||
input double max_drawdown = 0.1; // Maximum allowed drawdown as percentage of account balance
|
|
||||||
input bool resetCrossoverTradeOnDistance = false; // Reset trade count when price moves beyond distance threshold
|
|
||||||
input int resetCrossoverNumber = 0; // Number of trades to reset to when resetCrossoverTradeOnDistance is true
|
|
||||||
input double minimumLotSize = 0.01; // Minimum trade size allowed
|
|
||||||
input int maxTimeInPosition = 1; // Maximum time in hours to hold a position
|
|
||||||
input int tradeLengthThreshold = 31; // Time in minutes before considering a reverse trade
|
|
||||||
input int reverseTP = 707; // Take profit level for reverse trades (increased for BTC)
|
|
||||||
input int reverseLotSizeMultiplier = 4; // Multiplier for lot size in reverse trades
|
|
||||||
input int secondaryPositionHoldTime = 75; // Maximum time in minutes to hold a secondary position
|
|
||||||
// Global variables
|
|
||||||
int emaHandle; // EMA handle
|
|
||||||
double prevScore = 0; // Previous score
|
|
||||||
double currentScore = 0; // Current score
|
|
||||||
double emaPrevValue = 0; // Previous EMA value
|
|
||||||
double emaCurrentValue = 0; // Current EMA value
|
|
||||||
double emaSlope = 0; // EMA slope value
|
|
||||||
CTrade trade; // Trading object
|
|
||||||
|
|
||||||
datetime lastCrossoverTime = 0; // Time of last crossover
|
|
||||||
datetime lastTradeTime = 0; // Time of last trade
|
|
||||||
int crossoverTradeCount = 0; // Count of trades after each crossover
|
|
||||||
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Expert initialization function |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
int OnInit() {
|
|
||||||
// Create EMA handle (e.g., 14-period EMA on the closing price)
|
|
||||||
emaHandle = iMA(Symbol(), emaTimeFrame, emaPeriod, 0, MODE_EMA, PRICE_CLOSE);
|
|
||||||
|
|
||||||
if (emaHandle == INVALID_HANDLE) {
|
|
||||||
Print("Failed to create EMA handle");
|
|
||||||
return INIT_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
return INIT_SUCCEEDED;
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Expert deinitialization function |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void OnDeinit(const int reason) {
|
|
||||||
// Release the EMA handle
|
|
||||||
if (emaHandle != INVALID_HANDLE) {
|
|
||||||
ExpertRemove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Expert tick function |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void OnTick() {
|
|
||||||
// Buffer to hold the EMA values
|
|
||||||
double emaBuffer[];
|
|
||||||
|
|
||||||
// Get dynamic lot size based on current balance and max drawdown
|
|
||||||
double lotSize = CalculateLotSize();
|
|
||||||
|
|
||||||
if(lotSize < minimumLotSize) {
|
|
||||||
lotSize = minimumLotSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the current Ask and Bid prices
|
|
||||||
double Ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK);
|
|
||||||
double Bid = SymbolInfoDouble(Symbol(), SYMBOL_BID);
|
|
||||||
|
|
||||||
// Copy the last 2 EMA values (current and previous)
|
|
||||||
int copied = CopyBuffer(emaHandle, 0, 0, 2, emaBuffer);
|
|
||||||
if (copied < 2) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the current and previous EMA values
|
|
||||||
emaPrevValue = emaBuffer[1]; // Previous EMA value (index 1)
|
|
||||||
emaCurrentValue = emaBuffer[0]; // Current EMA value (index 0)
|
|
||||||
|
|
||||||
// Calculate the EMA slope (change in EMA values)
|
|
||||||
emaSlope = - (emaCurrentValue - emaPrevValue) * 100;
|
|
||||||
Print("EMA Slope: ", emaSlope);
|
|
||||||
|
|
||||||
// Check for price action crossover with EMA
|
|
||||||
double closePrev = iClose(Symbol(), Period(), 1); // Close of previous bar
|
|
||||||
double closeCurr = iClose(Symbol(), Period(), 0); // Close of current bar
|
|
||||||
|
|
||||||
// Check if enough time has passed for the cooldown (cooldownMinutes)
|
|
||||||
if (TimeCurrent() - lastCrossoverTime >= cooldownMinutes * 60) {
|
|
||||||
if (closePrev < emaPrevValue && closeCurr > emaCurrentValue) { // Bullish crossover
|
|
||||||
currentScore += crossOverStep;
|
|
||||||
crossoverTradeCount = 0; // Reset trade count after new crossover
|
|
||||||
lastCrossoverTime = TimeCurrent(); // Update the last crossover time
|
|
||||||
}
|
|
||||||
else if (closePrev > emaPrevValue && closeCurr < emaCurrentValue) { // Bearish crossover
|
|
||||||
currentScore -= crossOverStep;
|
|
||||||
crossoverTradeCount = 0; // Reset trade count after new crossover
|
|
||||||
lastCrossoverTime = TimeCurrent(); // Update the last crossover time
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check EMA slope
|
|
||||||
if (emaSlope > slopeThreshold) { // Positive slope
|
|
||||||
currentScore += slopeThresholdStep;
|
|
||||||
}
|
|
||||||
else if (emaSlope < -slopeThreshold) { // Negative slope
|
|
||||||
currentScore -= slopeThresholdStep;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (MathAbs(currentScore) > delayClampAbsolute) {
|
|
||||||
currentScore *= decayMultiplier;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ApplyTrailingStop) {
|
|
||||||
ApplyTrailingStop();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate distance to EMA and adjust score
|
|
||||||
double priceToEmaDistance = closeCurr - emaCurrentValue; // Distance between the current price and the EMA
|
|
||||||
Print("Price to EMA Distance: ", priceToEmaDistance);
|
|
||||||
|
|
||||||
if (MathAbs(priceToEmaDistance) > distanceThreshold) {
|
|
||||||
if (priceToEmaDistance > 0) { // Bullish (price above EMA)
|
|
||||||
currentScore += emaDistanceStep;
|
|
||||||
}
|
|
||||||
else if (priceToEmaDistance < 0) { // Bearish (price below EMA)
|
|
||||||
currentScore -= emaDistanceStep;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (currentScore > 0) {
|
|
||||||
currentScore -= emaDecayStep;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
currentScore += emaDecayStep;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close all positions if score crosses zero
|
|
||||||
if ((prevScore > 0 && currentScore <= 0) || (prevScore < 0 && currentScore >= 0)) {
|
|
||||||
Close_Position_MN(MagicNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the previous score
|
|
||||||
prevScore = currentScore;
|
|
||||||
|
|
||||||
if (crossoverTradeCount > maxCrossoverTrades) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Debounce check: Ensure enough time has passed since the last trade
|
|
||||||
if (TimeCurrent() - lastTradeTime >= tradeCooldownMinutes * 60) {
|
|
||||||
// Calculate ATR (Average True Range) for stop loss calculation
|
|
||||||
double atrArray[];
|
|
||||||
int atrPeriod = 14; // ATR period (can be adjusted)
|
|
||||||
int copied = CopyBuffer(iATR(Symbol(), Period(), atrPeriod), 0, 0, 1, atrArray);
|
|
||||||
if (copied < 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the current price (using Bid price)
|
|
||||||
double currentPrice = Bid;
|
|
||||||
// Get ATR value
|
|
||||||
double atrValue = atrArray[0]; // Latest ATR value
|
|
||||||
|
|
||||||
// Get the minimum stop level and freeze level for the symbol
|
|
||||||
int stopLevel = SymbolInfoInteger(Symbol(), SYMBOL_TRADE_STOPS_LEVEL);
|
|
||||||
int freezeLevel = SymbolInfoInteger(Symbol(), SYMBOL_TRADE_FREEZE_LEVEL);
|
|
||||||
|
|
||||||
// Calculate the minimum stop loss in price units (converted from pips)
|
|
||||||
double minStopLoss = stopLevel * SymbolInfoDouble(Symbol(), SYMBOL_POINT);
|
|
||||||
double minFreezeLevel = freezeLevel * SymbolInfoDouble(Symbol(), SYMBOL_POINT);
|
|
||||||
|
|
||||||
// Dynamic Stop Loss and Take Profit calculation based on ATR
|
|
||||||
double dynamicSL = atrValue * atrMultiplier;
|
|
||||||
double dynamicTP = atrValue * atrMultiplier;
|
|
||||||
|
|
||||||
// Adjust SL and TP if they are smaller than the minimum stop level
|
|
||||||
dynamicSL = MathMax(dynamicSL, minStopLoss);
|
|
||||||
dynamicTP = MathMax(dynamicTP, dynamicSL); // Ensure TP is at least the same as SL
|
|
||||||
|
|
||||||
// Trade logic based on the score
|
|
||||||
if (currentScore > scoreThreshold) { // Buy signal
|
|
||||||
if (PositionSelect(Symbol()) == false || !PositionGetInteger(POSITION_MAGIC) == MagicNumber && crossoverTradeCount < maxCrossoverTrades) {
|
|
||||||
// Open buy position with dynamic SL and TP
|
|
||||||
trade.SetExpertMagicNumber(MagicNumber);
|
|
||||||
if (trade.Buy(lotSize, Symbol(), currentPrice, Bid - dynamicSL, 0)) {
|
|
||||||
crossoverTradeCount++; // Increment trade count
|
|
||||||
lastTradeTime = TimeCurrent(); // Update the last trade time
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (currentScore < -scoreThreshold) { // Sell signal
|
|
||||||
if (PositionSelect(Symbol()) == false || !PositionGetInteger(POSITION_MAGIC) == MagicNumber && crossoverTradeCount < maxCrossoverTrades) {
|
|
||||||
// Open sell position with dynamic SL and TP
|
|
||||||
trade.SetExpertMagicNumber(MagicNumber);
|
|
||||||
if (trade.Sell(lotSize, Symbol(), currentPrice, Ask + dynamicSL, 0)) {
|
|
||||||
crossoverTradeCount++; // Increment trade count
|
|
||||||
lastTradeTime = TimeCurrent(); // Update the last trade time
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check existing positions for profit and place reverse trade if needed
|
|
||||||
CheckPositions();
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Check existing positions for profit and place reverse trade if needed |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void CheckPositions() {
|
|
||||||
// Check if there are any open positions
|
|
||||||
if (PositionsTotal() > 0) {
|
|
||||||
// Check if there are exactly 2 open positions
|
|
||||||
if (PositionsTotal() == 2) {
|
|
||||||
for (int i = 0; i < PositionsTotal(); i++) {
|
|
||||||
ulong ticket = PositionGetTicket(i);
|
|
||||||
if (PositionSelectByTicket(ticket)) {
|
|
||||||
datetime openTime = PositionGetInteger(POSITION_TIME);
|
|
||||||
int tradeLength = TimeCurrent() - openTime; // Trade duration in seconds
|
|
||||||
|
|
||||||
// Check if the trade has been open for more than the secondaryPositionHoldTime
|
|
||||||
if (tradeLength > secondaryPositionHoldTime * 60) { // Convert threshold to seconds
|
|
||||||
// Close all positions
|
|
||||||
CloseAllPositions();
|
|
||||||
return; // Exit the function after closing all positions
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (PositionsTotal() < 2) {
|
|
||||||
for (int i = 0; i < PositionsTotal(); i++) {
|
|
||||||
ulong ticket = PositionGetTicket(i);
|
|
||||||
if (PositionSelectByTicket(ticket)) {
|
|
||||||
double profit = PositionGetDouble(POSITION_PROFIT);
|
|
||||||
datetime openTime = PositionGetInteger(POSITION_TIME);
|
|
||||||
int tradeLength = TimeCurrent() - openTime; // Trade duration in seconds
|
|
||||||
|
|
||||||
// Check if the trade has been open for more than the tradeLengthThreshold
|
|
||||||
if (tradeLength > tradeLengthThreshold * 60) { // Convert threshold to seconds
|
|
||||||
double lotSize = PositionGetDouble(POSITION_VOLUME);
|
|
||||||
double newLotSize = lotSize * reverseLotSizeMultiplier; // 10 times the original lot size
|
|
||||||
|
|
||||||
crossoverTradeCount = maxCrossoverTrades + 1;
|
|
||||||
|
|
||||||
// Place a reverse trade
|
|
||||||
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) {
|
|
||||||
trade.SetExpertMagicNumber(MagicNumber);
|
|
||||||
if (trade.Sell(newLotSize, Symbol(), SymbolInfoDouble(Symbol(), SYMBOL_BID))) {
|
|
||||||
} else {
|
|
||||||
Print("Failed to execute reversal sell order");
|
|
||||||
}
|
|
||||||
} else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) {
|
|
||||||
trade.SetExpertMagicNumber(MagicNumber);
|
|
||||||
if (trade.Buy(newLotSize, Symbol(), SymbolInfoDouble(Symbol(), SYMBOL_ASK))) {
|
|
||||||
} else {
|
|
||||||
Print("Failed to execute reversal buy order");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close the trade if profit meets the take profit level
|
|
||||||
if (profit >= reverseTP) {
|
|
||||||
Close_Position_MN(MagicNumber);
|
|
||||||
CloseAllPositions();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if there is only one position and its volume is lotSize * reverseLotSizeMultiplier
|
|
||||||
if (PositionsTotal() == 1 && PositionGetDouble(POSITION_VOLUME) == minimumLotSize * reverseLotSizeMultiplier) {
|
|
||||||
trade.PositionClose(ticket);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the current Ask and Bid prices
|
|
||||||
double Ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK);
|
|
||||||
double Bid = SymbolInfoDouble(Symbol(), SYMBOL_BID);
|
|
||||||
|
|
||||||
// Check if the double down trade is exited by stop loss
|
|
||||||
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY && PositionGetDouble(POSITION_SL) > 0 && Bid <= PositionGetDouble(POSITION_SL)) {
|
|
||||||
// Close the original trade
|
|
||||||
CloseOriginalTrade();
|
|
||||||
} else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL && PositionGetDouble(POSITION_SL) > 0 && Ask >= PositionGetDouble(POSITION_SL)) {
|
|
||||||
// Close the original trade
|
|
||||||
CloseOriginalTrade();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to close the original trade
|
|
||||||
void CloseOriginalTrade() {
|
|
||||||
for (int i = PositionsTotal() - 1; i >= 0; i--) {
|
|
||||||
ulong ticket = PositionGetTicket(i);
|
|
||||||
if (PositionSelectByTicket(ticket)) {
|
|
||||||
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) {
|
|
||||||
trade.PositionClose(ticket);
|
|
||||||
} else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) {
|
|
||||||
trade.PositionClose(ticket);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Function to close all positions |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void CloseAllPositions() {
|
|
||||||
// Loop through all positions and close them
|
|
||||||
for (int i = PositionsTotal() - 1; i >= 0; i--) {
|
|
||||||
ulong ticket = PositionGetTicket(i);
|
|
||||||
if (PositionSelectByTicket(ticket)) {
|
|
||||||
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) {
|
|
||||||
trade.PositionClose(ticket);
|
|
||||||
}
|
|
||||||
else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) {
|
|
||||||
trade.PositionClose(ticket);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ApplyTrailingStop()
|
|
||||||
{
|
|
||||||
for(int i=PositionsTotal()-1; i>=0; i--)
|
|
||||||
{
|
|
||||||
string symbol = PositionGetSymbol(i);
|
|
||||||
ulong PositionTicket = PositionGetTicket(i);
|
|
||||||
long trade_type = PositionGetInteger(POSITION_TYPE);
|
|
||||||
|
|
||||||
if(!PositionGetInteger(POSITION_MAGIC) == MagicNumber) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
double POINT = SymbolInfoDouble( symbol, SYMBOL_POINT );
|
|
||||||
int DIGIT = (int) SymbolInfoInteger( symbol, SYMBOL_DIGITS );
|
|
||||||
|
|
||||||
if(trade_type == 0)
|
|
||||||
{
|
|
||||||
double Bid = NormalizeDouble(SymbolInfoDouble(symbol,SYMBOL_BID),DIGIT);
|
|
||||||
|
|
||||||
if(Bid-PositionGetDouble(POSITION_PRICE_OPEN) > NormalizeDouble(POINT * TrailingStop,DIGIT))
|
|
||||||
{
|
|
||||||
if(PositionGetDouble(POSITION_SL) < NormalizeDouble(Bid - POINT * TrailingStop,DIGIT))
|
|
||||||
{
|
|
||||||
trade.PositionModify(PositionTicket,NormalizeDouble(Bid - POINT * TrailingStop,DIGIT),PositionGetDouble(POSITION_TP));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(trade_type == 1)
|
|
||||||
{
|
|
||||||
double Ask = NormalizeDouble(SymbolInfoDouble(symbol,SYMBOL_ASK),DIGIT);
|
|
||||||
|
|
||||||
if((PositionGetDouble(POSITION_PRICE_OPEN) - Ask) > NormalizeDouble( POINT * TrailingStop,DIGIT))
|
|
||||||
{
|
|
||||||
if((PositionGetDouble(POSITION_SL) > NormalizeDouble(Ask + POINT * TrailingStop,DIGIT)) || (PositionGetDouble(POSITION_SL)==0))
|
|
||||||
{
|
|
||||||
trade.PositionModify(PositionTicket,NormalizeDouble(Ask + POINT * TrailingStop,DIGIT),PositionGetDouble(POSITION_TP));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Close_Position_MN(ulong magicNumber)
|
|
||||||
{
|
|
||||||
int total = PositionsTotal();
|
|
||||||
for(int i = total - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
ulong ticket = PositionGetTicket(i);
|
|
||||||
|
|
||||||
// Use PositionSelect by symbol instead of ticket
|
|
||||||
string symbol = PositionGetSymbol(i);
|
|
||||||
if(PositionSelect(symbol))
|
|
||||||
{
|
|
||||||
if (PositionGetInteger(POSITION_MAGIC) == magicNumber && PositionGetInteger(POSITION_TICKET) == ticket)
|
|
||||||
{
|
|
||||||
if(symbol == _Symbol) // Verify the symbol
|
|
||||||
{
|
|
||||||
trade.PositionClose(ticket);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Calculate the dynamic lot size based on max drawdown |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
double CalculateLotSize()
|
|
||||||
{
|
|
||||||
double balance = AccountInfoDouble(ACCOUNT_BALANCE); // Get account balance
|
|
||||||
double allowedDrawdown = balance * max_drawdown; // Calculate allowed drawdown in account currency
|
|
||||||
double baseDrawdownPerLot = 150; // Assumed drawdown per 0.01 lots as per backtest
|
|
||||||
|
|
||||||
// Calculate lot size based on maximum drawdown
|
|
||||||
double lotSize = (allowedDrawdown / baseDrawdownPerLot) * 0.01;
|
|
||||||
return NormalizeDouble(lotSize, 2); // Normalize lot size to 2 decimal places
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 276 KiB |
@@ -1,456 +0,0 @@
|
|||||||
//+------------------------------------------------------------------+
|
|
||||||
//| ScoringTrade.mq5 |
|
|
||||||
//| Generated by ChatGPT |
|
|
||||||
//| |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
#property strict
|
|
||||||
#include <Trade\Trade.mqh>
|
|
||||||
|
|
||||||
// Input parameters
|
|
||||||
input int MagicNumber = 42;
|
|
||||||
input int scoreThreshold = 5200; // Score threshold for trade entry
|
|
||||||
input int slopeThreshold = 93; // EMA slope threshold
|
|
||||||
input double maxScore = 7900; // Max score value for clamping
|
|
||||||
input int cooldownMinutes = 18; // Cooldown period in minutes (37 minutes)
|
|
||||||
input int tradeCooldownMinutes = 24; // Trade debounce cooldown period (5 minutes)
|
|
||||||
input ENUM_TIMEFRAMES emaTimeFrame = PERIOD_H1; // EMA Timeframe
|
|
||||||
input double delayClampAbsolute = 1690;
|
|
||||||
input int emaPeriod = 64; // EMA period
|
|
||||||
input double crossOverStep = 950;
|
|
||||||
input double slopeThresholdStep = 635;
|
|
||||||
input double emaDistanceStep = 150;
|
|
||||||
input double emaDecayStep = 0;
|
|
||||||
input double decayMultiplier = 0.08; // Decay multiplier
|
|
||||||
input double distanceThreshold = 28.5; // Set your distance threshold (adjust as necessary)
|
|
||||||
input double atrMultiplier = 7.6; // Multiplier for dynamic SL and TP calculation
|
|
||||||
input double TrailingStop = 5;
|
|
||||||
input bool ApplyTrailingStop = true;
|
|
||||||
input int maxCrossoverTrades = 4; // Maximum number of trades per crossover
|
|
||||||
input double max_drawdown = 0.1; // Maximum drawdown percentage
|
|
||||||
input bool resetCrossoverTradeOnDistance = false;
|
|
||||||
input int resetCrossoverNumber = 0;
|
|
||||||
input double minimumLotSize = 0.01;
|
|
||||||
input int maxTimeInPosition = 9;
|
|
||||||
input int tradeLengthThreshold = 98;
|
|
||||||
input int reverseTP = 32;
|
|
||||||
input int reverseLotSizeMultiplier = 15;
|
|
||||||
input int secondaryPositionHoldTime = 32;
|
|
||||||
// Global variables
|
|
||||||
int emaHandle; // EMA handle
|
|
||||||
double prevScore = 0; // Previous score
|
|
||||||
double currentScore = 0; // Current score
|
|
||||||
double emaPrevValue = 0; // Previous EMA value
|
|
||||||
double emaCurrentValue = 0; // Current EMA value
|
|
||||||
double emaSlope = 0; // EMA slope value
|
|
||||||
CTrade trade; // Trading object
|
|
||||||
|
|
||||||
datetime lastCrossoverTime = 0; // Time of last crossover
|
|
||||||
datetime lastTradeTime = 0; // Time of last trade
|
|
||||||
int crossoverTradeCount = 0; // Count of trades after each crossover
|
|
||||||
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Expert initialization function |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
int OnInit() {
|
|
||||||
// Create EMA handle (e.g., 14-period EMA on the closing price)
|
|
||||||
emaHandle = iMA(Symbol(), emaTimeFrame, emaPeriod, 0, MODE_EMA, PRICE_CLOSE);
|
|
||||||
|
|
||||||
if (emaHandle == INVALID_HANDLE) {
|
|
||||||
Print("Failed to create EMA handle");
|
|
||||||
return INIT_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
return INIT_SUCCEEDED;
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Expert deinitialization function |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void OnDeinit(const int reason) {
|
|
||||||
// Release the EMA handle
|
|
||||||
if (emaHandle != INVALID_HANDLE) {
|
|
||||||
ExpertRemove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Expert tick function |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void OnTick() {
|
|
||||||
// Buffer to hold the EMA values
|
|
||||||
double emaBuffer[];
|
|
||||||
|
|
||||||
// Get dynamic lot size based on current balance and max drawdown
|
|
||||||
double lotSize = CalculateLotSize();
|
|
||||||
|
|
||||||
if(lotSize < minimumLotSize) {
|
|
||||||
lotSize = minimumLotSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the current Ask and Bid prices
|
|
||||||
double Ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK);
|
|
||||||
double Bid = SymbolInfoDouble(Symbol(), SYMBOL_BID);
|
|
||||||
|
|
||||||
// Copy the last 2 EMA values (current and previous)
|
|
||||||
int copied = CopyBuffer(emaHandle, 0, 0, 2, emaBuffer);
|
|
||||||
if (copied < 2) {
|
|
||||||
Print("Failed to copy EMA values. Error code: ", GetLastError());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the current and previous EMA values
|
|
||||||
emaPrevValue = emaBuffer[1]; // Previous EMA value (index 1)
|
|
||||||
emaCurrentValue = emaBuffer[0]; // Current EMA value (index 0)
|
|
||||||
|
|
||||||
// Calculate the EMA slope (change in EMA values)
|
|
||||||
emaSlope = - (emaCurrentValue - emaPrevValue) * 100;
|
|
||||||
|
|
||||||
// Check for price action crossover with EMA
|
|
||||||
double closePrev = iClose(Symbol(), Period(), 1); // Close of previous bar
|
|
||||||
double closeCurr = iClose(Symbol(), Period(), 0); // Close of current bar
|
|
||||||
|
|
||||||
// Check if enough time has passed for the cooldown (cooldownMinutes)
|
|
||||||
if (TimeCurrent() - lastCrossoverTime >= cooldownMinutes * 60) {
|
|
||||||
if (closePrev < emaPrevValue && closeCurr > emaCurrentValue) { // Bullish crossover
|
|
||||||
Print("Bullish crossover");
|
|
||||||
currentScore += crossOverStep;
|
|
||||||
crossoverTradeCount = 0; // Reset trade count after new crossover
|
|
||||||
lastCrossoverTime = TimeCurrent(); // Update the last crossover time
|
|
||||||
}
|
|
||||||
else if (closePrev > emaPrevValue && closeCurr < emaCurrentValue) { // Bearish crossover
|
|
||||||
Print("Bearish crossover");
|
|
||||||
currentScore -= crossOverStep;
|
|
||||||
crossoverTradeCount = 0; // Reset trade count after new crossover
|
|
||||||
lastCrossoverTime = TimeCurrent(); // Update the last crossover time
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check EMA slope
|
|
||||||
if (emaSlope > slopeThreshold) { // Positive slope
|
|
||||||
currentScore += slopeThresholdStep;
|
|
||||||
}
|
|
||||||
else if (emaSlope < -slopeThreshold) { // Negative slope
|
|
||||||
currentScore -= slopeThresholdStep;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (MathAbs(currentScore) > delayClampAbsolute) {
|
|
||||||
currentScore *= decayMultiplier;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ApplyTrailingStop) {
|
|
||||||
ApplyTrailingStop();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate distance to EMA and adjust score
|
|
||||||
double priceToEmaDistance = closeCurr - emaCurrentValue; // Distance between the current price and the EMA
|
|
||||||
|
|
||||||
if (MathAbs(priceToEmaDistance) > distanceThreshold) {
|
|
||||||
if (priceToEmaDistance > 0) { // Bullish (price above EMA)
|
|
||||||
currentScore += emaDistanceStep;
|
|
||||||
Print("Bullish distance score added. Price: ", closeCurr, " EMA: ", emaCurrentValue);
|
|
||||||
}
|
|
||||||
else if (priceToEmaDistance < 0) { // Bearish (price below EMA)
|
|
||||||
currentScore -= emaDistanceStep;
|
|
||||||
Print("Bearish distance score added. Price: ", closeCurr, " EMA: ", emaCurrentValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (currentScore > 0) {
|
|
||||||
currentScore -= emaDecayStep;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
currentScore += emaDecayStep;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close all positions if score crosses zero
|
|
||||||
if ((prevScore > 0 && currentScore <= 0) || (prevScore < 0 && currentScore >= 0)) {
|
|
||||||
Close_Position_MN(MagicNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the previous score
|
|
||||||
prevScore = currentScore;
|
|
||||||
|
|
||||||
if (crossoverTradeCount > maxCrossoverTrades) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Debounce check: Ensure enough time has passed since the last trade
|
|
||||||
if (TimeCurrent() - lastTradeTime >= tradeCooldownMinutes * 60) {
|
|
||||||
// Calculate ATR (Average True Range) for stop loss calculation
|
|
||||||
double atrArray[];
|
|
||||||
int atrPeriod = 14; // ATR period (can be adjusted)
|
|
||||||
int copied = CopyBuffer(iATR(Symbol(), Period(), atrPeriod), 0, 0, 1, atrArray);
|
|
||||||
if (copied < 1) {
|
|
||||||
Print("Failed to get ATR values. Error code: ", GetLastError());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the current price (using Bid price)
|
|
||||||
double currentPrice = Bid;
|
|
||||||
// Get ATR value
|
|
||||||
double atrValue = atrArray[0]; // Latest ATR value
|
|
||||||
|
|
||||||
// Get the minimum stop level and freeze level for the symbol
|
|
||||||
int stopLevel = SymbolInfoInteger(Symbol(), SYMBOL_TRADE_STOPS_LEVEL);
|
|
||||||
int freezeLevel = SymbolInfoInteger(Symbol(), SYMBOL_TRADE_FREEZE_LEVEL);
|
|
||||||
|
|
||||||
// Calculate the minimum stop loss in price units (converted from pips)
|
|
||||||
double minStopLoss = stopLevel * SymbolInfoDouble(Symbol(), SYMBOL_POINT);
|
|
||||||
double minFreezeLevel = freezeLevel * SymbolInfoDouble(Symbol(), SYMBOL_POINT);
|
|
||||||
|
|
||||||
// Dynamic Stop Loss and Take Profit calculation based on ATR
|
|
||||||
double dynamicSL = atrValue * atrMultiplier;
|
|
||||||
double dynamicTP = atrValue * atrMultiplier;
|
|
||||||
|
|
||||||
// Adjust SL and TP if they are smaller than the minimum stop level
|
|
||||||
dynamicSL = MathMax(dynamicSL, minStopLoss);
|
|
||||||
dynamicTP = MathMax(dynamicTP, dynamicSL); // Ensure TP is at least the same as SL
|
|
||||||
|
|
||||||
// Trade logic based on the score
|
|
||||||
if (currentScore > scoreThreshold) { // Buy signal
|
|
||||||
if (PositionSelect(Symbol()) == false || !PositionGetInteger(POSITION_MAGIC) == MagicNumber && crossoverTradeCount < maxCrossoverTrades) {
|
|
||||||
Print("maxCrossover");
|
|
||||||
Print(crossoverTradeCount);
|
|
||||||
// Open buy position with dynamic SL and TP
|
|
||||||
trade.SetExpertMagicNumber(MagicNumber);
|
|
||||||
if (trade.Buy(lotSize, Symbol(), currentPrice, Bid - dynamicSL, 0)) {
|
|
||||||
Print("Buy order executed with score: ", currentScore);
|
|
||||||
crossoverTradeCount++; // Increment trade count
|
|
||||||
lastTradeTime = TimeCurrent(); // Update the last trade time
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (currentScore < -scoreThreshold) { // Sell signal
|
|
||||||
if (PositionSelect(Symbol()) == false || !PositionGetInteger(POSITION_MAGIC) == MagicNumber && crossoverTradeCount < maxCrossoverTrades) {
|
|
||||||
Print("maxCrossover");
|
|
||||||
Print(crossoverTradeCount);
|
|
||||||
// Open sell position with dynamic SL and TP
|
|
||||||
trade.SetExpertMagicNumber(MagicNumber);
|
|
||||||
if (trade.Sell(lotSize, Symbol(), currentPrice, Ask + dynamicSL, 0)) {
|
|
||||||
Print("Sell order executed with score: ", currentScore);
|
|
||||||
crossoverTradeCount++; // Increment trade count
|
|
||||||
lastTradeTime = TimeCurrent(); // Update the last trade time
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Print("Trade skipped due to debounce: ", currentScore);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check existing positions for profit and place reverse trade if needed
|
|
||||||
CheckPositions();
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Check existing positions for profit and place reverse trade if needed |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Check existing positions for duration and place reverse trade if needed |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void CheckPositions() {
|
|
||||||
// Check if there are any open positions
|
|
||||||
if (PositionsTotal() > 0) {
|
|
||||||
// Check if there are exactly 2 open positions
|
|
||||||
if (PositionsTotal() == 2) {
|
|
||||||
for (int i = 0; i < PositionsTotal(); i++) {
|
|
||||||
ulong ticket = PositionGetTicket(i);
|
|
||||||
if (PositionSelectByTicket(ticket)) {
|
|
||||||
datetime openTime = PositionGetInteger(POSITION_TIME);
|
|
||||||
int tradeLength = TimeCurrent() - openTime; // Trade duration in seconds
|
|
||||||
|
|
||||||
// Check if the trade has been open for more than the secondaryPositionHoldTime
|
|
||||||
if (tradeLength > secondaryPositionHoldTime * 60) { // Convert threshold to seconds
|
|
||||||
// Close all positions
|
|
||||||
CloseAllPositions();
|
|
||||||
Print("All positions closed due to exceeding secondaryPositionHoldTime");
|
|
||||||
return; // Exit the function after closing all positions
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (PositionsTotal() < 2) {
|
|
||||||
for (int i = 0; i < PositionsTotal(); i++) {
|
|
||||||
ulong ticket = PositionGetTicket(i);
|
|
||||||
if (PositionSelectByTicket(ticket)) {
|
|
||||||
double profit = PositionGetDouble(POSITION_PROFIT);
|
|
||||||
datetime openTime = PositionGetInteger(POSITION_TIME);
|
|
||||||
int tradeLength = TimeCurrent() - openTime; // Trade duration in seconds
|
|
||||||
|
|
||||||
// Check if the trade has been open for more than the tradeLengthThreshold
|
|
||||||
if (tradeLength > tradeLengthThreshold * 60) { // Convert threshold to seconds
|
|
||||||
double lotSize = PositionGetDouble(POSITION_VOLUME);
|
|
||||||
double newLotSize = lotSize * reverseLotSizeMultiplier; // 10 times the original lot size
|
|
||||||
|
|
||||||
crossoverTradeCount = maxCrossoverTrades + 1;
|
|
||||||
|
|
||||||
// Place a reverse trade
|
|
||||||
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) {
|
|
||||||
trade.SetExpertMagicNumber(MagicNumber);
|
|
||||||
if (trade.Sell(newLotSize, Symbol(), SymbolInfoDouble(Symbol(), SYMBOL_BID))) {
|
|
||||||
Print("Reversal sell order executed with increased lot size");
|
|
||||||
} else {
|
|
||||||
Print("Failed to execute reversal sell order");
|
|
||||||
}
|
|
||||||
} else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) {
|
|
||||||
trade.SetExpertMagicNumber(MagicNumber);
|
|
||||||
if (trade.Buy(newLotSize, Symbol(), SymbolInfoDouble(Symbol(), SYMBOL_ASK))) {
|
|
||||||
Print("Reversal buy order executed with increased lot size");
|
|
||||||
} else {
|
|
||||||
Print("Failed to execute reversal buy order");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close the trade if profit meets the take profit level
|
|
||||||
if (profit >= reverseTP) {
|
|
||||||
Close_Position_MN(MagicNumber);
|
|
||||||
CloseAllPositions();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if there is only one position and its volume is lotSize * reverseLotSizeMultiplier
|
|
||||||
if (PositionsTotal() == 1 && PositionGetDouble(POSITION_VOLUME) == minimumLotSize * reverseLotSizeMultiplier) {
|
|
||||||
trade.PositionClose(ticket);
|
|
||||||
Print("Single position with volume equal to lotSize * reverseLotSizeMultiplier closed");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the current Ask and Bid prices
|
|
||||||
double Ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK);
|
|
||||||
double Bid = SymbolInfoDouble(Symbol(), SYMBOL_BID);
|
|
||||||
|
|
||||||
|
|
||||||
// Check if the double down trade is exited by stop loss
|
|
||||||
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY && PositionGetDouble(POSITION_SL) > 0 && Bid <= PositionGetDouble(POSITION_SL)) {
|
|
||||||
// Close the original trade
|
|
||||||
CloseOriginalTrade();
|
|
||||||
} else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL && PositionGetDouble(POSITION_SL) > 0 && Ask >= PositionGetDouble(POSITION_SL)) {
|
|
||||||
// Close the original trade
|
|
||||||
CloseOriginalTrade();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to close the original trade
|
|
||||||
void CloseOriginalTrade() {
|
|
||||||
for (int i = PositionsTotal() - 1; i >= 0; i--) {
|
|
||||||
ulong ticket = PositionGetTicket(i);
|
|
||||||
if (PositionSelectByTicket(ticket)) {
|
|
||||||
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) {
|
|
||||||
trade.PositionClose(ticket);
|
|
||||||
Print("Original buy position closed due to double down stop loss.");
|
|
||||||
} else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) {
|
|
||||||
trade.PositionClose(ticket);
|
|
||||||
Print("Original sell position closed due to double down stop loss.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Function to close all positions |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void CloseAllPositions() {
|
|
||||||
// Loop through all positions and close them
|
|
||||||
for (int i = PositionsTotal() - 1; i >= 0; i--) {
|
|
||||||
ulong ticket = PositionGetTicket(i);
|
|
||||||
if (PositionSelectByTicket(ticket)) {
|
|
||||||
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) {
|
|
||||||
trade.PositionClose(ticket);
|
|
||||||
Print("Buy position closed at score crossover.");
|
|
||||||
}
|
|
||||||
else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) {
|
|
||||||
trade.PositionClose(ticket);
|
|
||||||
Print("Sell position closed at score crossover.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ApplyTrailingStop()
|
|
||||||
{
|
|
||||||
for(int i=PositionsTotal()-1; i>=0; i--)
|
|
||||||
{
|
|
||||||
string symbol = PositionGetSymbol(i);
|
|
||||||
ulong PositionTicket = PositionGetTicket(i);
|
|
||||||
long trade_type = PositionGetInteger(POSITION_TYPE);
|
|
||||||
|
|
||||||
if(!PositionGetInteger(POSITION_MAGIC) == MagicNumber) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
double POINT = SymbolInfoDouble( symbol, SYMBOL_POINT );
|
|
||||||
int DIGIT = (int) SymbolInfoInteger( symbol, SYMBOL_DIGITS );
|
|
||||||
|
|
||||||
|
|
||||||
if(trade_type == 0)
|
|
||||||
{
|
|
||||||
double Bid = NormalizeDouble(SymbolInfoDouble(symbol,SYMBOL_BID),DIGIT);
|
|
||||||
|
|
||||||
if(Bid-PositionGetDouble(POSITION_PRICE_OPEN) > NormalizeDouble(POINT * TrailingStop,DIGIT))
|
|
||||||
{
|
|
||||||
if(PositionGetDouble(POSITION_SL) < NormalizeDouble(Bid - POINT * TrailingStop,DIGIT))
|
|
||||||
{
|
|
||||||
trade.PositionModify(PositionTicket,NormalizeDouble(Bid - POINT * TrailingStop,DIGIT),PositionGetDouble(POSITION_TP));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(trade_type == 1)
|
|
||||||
{
|
|
||||||
double Ask = NormalizeDouble(SymbolInfoDouble(symbol,SYMBOL_ASK),DIGIT);
|
|
||||||
|
|
||||||
if((PositionGetDouble(POSITION_PRICE_OPEN) - Ask) > NormalizeDouble( POINT * TrailingStop,DIGIT))
|
|
||||||
{
|
|
||||||
if((PositionGetDouble(POSITION_SL) > NormalizeDouble(Ask + POINT * TrailingStop,DIGIT)) || (PositionGetDouble(POSITION_SL)==0))
|
|
||||||
{
|
|
||||||
trade.PositionModify(PositionTicket,NormalizeDouble(Ask + POINT * TrailingStop,DIGIT),PositionGetDouble(POSITION_TP));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Close_Position_MN(ulong magicNumber)
|
|
||||||
{
|
|
||||||
int total = PositionsTotal();
|
|
||||||
for(int i = total - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
ulong ticket = PositionGetTicket(i);
|
|
||||||
|
|
||||||
// Use PositionSelect by symbol instead of ticket
|
|
||||||
string symbol = PositionGetSymbol(i);
|
|
||||||
if(PositionSelect(symbol))
|
|
||||||
{
|
|
||||||
if (PositionGetInteger(POSITION_MAGIC) == magicNumber && PositionGetInteger(POSITION_TICKET) == ticket)
|
|
||||||
{
|
|
||||||
if(symbol == _Symbol) // Verify the symbol
|
|
||||||
{
|
|
||||||
Print("MN " + magicNumber);
|
|
||||||
trade.PositionClose(ticket);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int errorCode = GetLastError();
|
|
||||||
Print("aaaa PositionSelect failed with error code: ", errorCode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Calculate the dynamic lot size based on max drawdown |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
double CalculateLotSize()
|
|
||||||
{
|
|
||||||
double balance = AccountInfoDouble(ACCOUNT_BALANCE); // Get account balance
|
|
||||||
double allowedDrawdown = balance * max_drawdown; // Calculate allowed drawdown in account currency
|
|
||||||
double baseDrawdownPerLot = 150; // Assumed drawdown per 0.01 lots as per backtest
|
|
||||||
|
|
||||||
// Calculate lot size based on maximum drawdown
|
|
||||||
double lotSize = (allowedDrawdown / baseDrawdownPerLot) * 0.01;
|
|
||||||
return NormalizeDouble(lotSize, 2); // Normalize lot size to 2 decimal places
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 321 KiB |
@@ -1,661 +1,198 @@
|
|||||||
# Table of Contents
|
# Table of Contents
|
||||||
|
|
||||||
- [Table of Contents](#table-of-contents)
|
- [Table of Contents](#table-of-contents)
|
||||||
- [Profitable Expert Advisors Collection](#profitable-expert-advisors-collection)
|
- [Profitable Expert Advisors (EAs)](#profitable-expert-advisors-eas)
|
||||||
- [Project Overview](#project-overview)
|
- [Available EAs](#available-eas)
|
||||||
- [Available Expert Advisors](#available-expert-advisors)
|
- [1. RSI Reversal Asian AUD/USD](#1-rsi-reversal-asian-audusd)
|
||||||
- [1. RSI Divergence Rebound](#1-rsi-divergence-rebound)
|
- [2. RSI MidPoint Hijack XAU/USD](#2-rsi-midpoint-hijack-xauusd)
|
||||||
- [2. EMA Crossover Skirmish](#2-ema-crossover-skirmish)
|
- [3. RSI Reversal Asian EUR/USD](#3-rsi-reversal-asian-eurusd)
|
||||||
- [3. RSI Divergence Extrema AUDUSD](#3-rsi-divergence-extrema-audusd)
|
- [4. RSI CrossOver Reversal XAU/USD](#4-rsi-crossover-reversal-xauusd)
|
||||||
- [4. RSI Divergence Extrema EURUSD](#4-rsi-divergence-extrema-eurusd)
|
- [Strategy Rationale](#strategy-rationale)
|
||||||
- [5. RSI Reversal Asian AUDUSD](#5-rsi-reversal-asian-audusd)
|
- [RSI Reversal Strategy](#rsi-reversal-strategy)
|
||||||
- [6. RSI Reversal Asian EURUSD](#6-rsi-reversal-asian-eurusd)
|
- [RSI MidPoint Hijack Strategy](#rsi-midpoint-hijack-strategy)
|
||||||
- [7. EMA Crossover BTC](#7-ema-crossover-btc)
|
- [Profitability Factors](#profitability-factors)
|
||||||
- [8. Smart RSI BTC](#8-smart-rsi-btc)
|
- [Usage](#usage)
|
||||||
- [9. RSI MidPoint Hijack](#9-rsi-midpoint-hijack)
|
|
||||||
- [Technical Details](#technical-details)
|
|
||||||
- [Requirements](#requirements)
|
|
||||||
- [Installation](#installation)
|
|
||||||
- [Disclaimer](#disclaimer)
|
- [Disclaimer](#disclaimer)
|
||||||
|
|
||||||
|
|
||||||
# Profitable Expert Advisors Collection
|
# Profitable Expert Advisors (EAs)
|
||||||
|
|
||||||
## Project Overview
|
This repository contains a collection of profitable Expert Advisors (EAs) designed for MetaTrader 5. Each EA implements different trading strategies optimized for specific currency pairs and market conditions.
|
||||||
This repository contains a collection of profitable MetaTrader 5 (MT5) Expert Advisors, each implementing different trading strategies. These EAs have been developed and tested for optimal performance in various market conditions.
|
|
||||||
|
## Available EAs
|
||||||
## Available Expert Advisors
|
|
||||||
|
### 1. RSI Reversal Asian AUD/USD
|
||||||
### 1. RSI Divergence Rebound
|
- **Strategy**: RSI-based reversal trading during Asian session
|
||||||
A strategy that combines RSI (Relative Strength Index) divergence detection with price action analysis to identify potential reversal points in the market.
|
- **Key Features**:
|
||||||
|
- Uses RSI (Relative Strength Index) for entry and exit signals
|
||||||
**Key Features:**
|
- Specifically optimized for AUD/USD pair during Asian session (00:00-08:00 UTC)
|
||||||
- RSI divergence patterns detection (bullish and bearish)
|
- Implements strict risk management with configurable stop loss and take profit
|
||||||
- Price rebound confirmation
|
- Includes spread monitoring to avoid trading during high spread conditions
|
||||||
- Risk management through stop loss and take profit levels
|
- Features a visual panel showing real-time trading metrics
|
||||||
|
|
||||||
**Strategy Settings:**
|
**Core Parameters:**
|
||||||
- Symbol: XAUUSD
|
```mql5
|
||||||
- Period: H1 (2021.01.01 - 2025.01.01)
|
// RSI Settings
|
||||||
- RSI Period: 14
|
RSIPeriod = 28; // RSI period
|
||||||
- RSI Overbought: 70
|
OverboughtLevel = 64; // Overbought level
|
||||||
- RSI Oversold: 30
|
OversoldLevel = 13; // Oversold level
|
||||||
- Base Lot Size: 0.01
|
|
||||||
- ATR Period: 14
|
// Risk Management
|
||||||
- ATR SL Multiplier: 3
|
TakeProfitPips = 175; // Take profit in pips
|
||||||
- ATR TP Multiplier: 10
|
StopLossPips = 5; // Stop loss in pips
|
||||||
- Max Spread: 50
|
MaxLotSize = 0.1; // Maximum lot size
|
||||||
- Divergence Lookback: 9
|
MaxSpread = 1000; // Maximum allowed spread in pips
|
||||||
- Min Trade Interval: 30
|
MaxDuration = 140; // Maximum trade duration in hours
|
||||||
- Max Risk Percent: 2%
|
```
|
||||||
- Max Drawdown Percent: 10%
|
|
||||||
- Max Consecutive Losses: 3
|
**Test Balance Results:**
|
||||||
- Max Lot Size: 0.1
|
<div align="center">
|
||||||
|
<img src="RSIReversalAsianAUDUSD/test-balance.jpg" alt="RSI Reversal Asian AUD/USD Test Balance" width="600"/>
|
||||||
**Performance Metrics (2021-2025):**
|
</div>
|
||||||
| Metric | Value |
|
|
||||||
|--------|-------|
|
### 2. RSI MidPoint Hijack XAU/USD
|
||||||
| Total Net Profit | $1,344.74 |
|
- **Strategy**: Multi-strategy approach combining RSI and EMA crossovers
|
||||||
| Gross Profit | $4,410.51 |
|
- **Key Features**:
|
||||||
| Gross Loss | -$3,065.77 |
|
- Implements three distinct strategies:
|
||||||
| Profit Factor | 1.44 |
|
1. RSI Follow Strategy
|
||||||
| Recovery Factor | 4.91 |
|
2. RSI Reverse Strategy
|
||||||
| Expected Payoff | $4.87 |
|
3. EMA Cross Strategy
|
||||||
| Sharpe Ratio | 1.69 |
|
- Optimized for Gold (XAU/USD) trading
|
||||||
| AHPR | 1.0033 (0.33%) |
|
- Includes strategy locking mechanism to protect profits
|
||||||
| GHPR | 1.0031 (0.31%) |
|
- Features cooldown periods after losses
|
||||||
|
- Time-based trading windows for each strategy
|
||||||
**Trade Statistics (2021-2025):**
|
|
||||||
| Statistic | Value |
|
**Core Parameters:**
|
||||||
|-----------|-------|
|
```mql5
|
||||||
| Total Trades | 276 |
|
// RSI Follow Strategy
|
||||||
| Total Deals | 552 |
|
InpRSIPeriod = 87; // RSI Period
|
||||||
| Profit Trades | 81 (29.35%) |
|
InpRSIOverbought = 72; // RSI Overbought Level
|
||||||
| Loss Trades | 195 (70.65%) |
|
InpRSIOversold = 50; // RSI Oversold Level
|
||||||
| Short Trades Won | 26.28% |
|
|
||||||
| Long Trades Won | 32.37% |
|
// RSI Reverse Strategy
|
||||||
| Largest Profit Trade | $144.46 |
|
InpRSIReversePeriod = 59; // RSI Period
|
||||||
| Largest Loss Trade | -$46.66 |
|
InpRSIReverseOverbought = 51; // RSI Overbought Level
|
||||||
| Average Profit Trade | $54.45 |
|
InpRSIReverseOversold = 49; // RSI Oversold Level
|
||||||
| Average Loss Trade | -$15.72 |
|
|
||||||
| Max Consecutive Wins | 3 ($179.71) |
|
// Strategy Management
|
||||||
| Max Consecutive Losses | 15 (-$159.89) |
|
InpEnableStrategyLock = false; // Enable Strategy Lock
|
||||||
|
InpLockProfitThreshold = 0.0; // Lock Profit Threshold (pips)
|
||||||
**Drawdown Analysis (2021-2025):**
|
```
|
||||||
| Metric | Value |
|
|
||||||
|--------|-------|
|
**Test Balance Results:**
|
||||||
| Balance Drawdown Absolute | $18.62 |
|
<div align="center">
|
||||||
| Equity Drawdown Absolute | $19.45 |
|
<img src="RSIMidPointHijackXAUUSD/test-balance.jpg" alt="RSI MidPoint Hijack XAU/USD Test Balance" width="600"/>
|
||||||
| Balance Drawdown Maximal | $231.79 (10.21%) |
|
</div>
|
||||||
| Equity Drawdown Maximal | $273.75 (11.93%) |
|
|
||||||
| Balance Drawdown Relative | 13.47% ($210.14) |
|
### 3. RSI Reversal Asian EUR/USD
|
||||||
| Equity Drawdown Relative | 15.85% ($250.78) |
|
- **Strategy**: Similar to AUD/USD version but optimized for EUR/USD
|
||||||
|
- **Key Features**:
|
||||||
**Balance Sheet (2021-2025):**
|
- RSI-based reversal strategy during Asian session
|
||||||

|
- Customized parameters for EUR/USD pair
|
||||||
|
- Risk management features
|
||||||
### 2. EMA Crossover Skirmish
|
- Session-based trading
|
||||||
A strategy that uses Exponential Moving Average (EMA) crossovers with advanced scoring and position management.
|
|
||||||
|
**Core Parameters:**
|
||||||
**Key Features:**
|
```mql5
|
||||||
- EMA crossover detection
|
// RSI Settings
|
||||||
- Advanced scoring system
|
RSIPeriod = 14; // RSI period
|
||||||
- Trailing stop management
|
OverboughtLevel = 78; // Overbought level
|
||||||
- Position scaling and reversal capabilities
|
OversoldLevel = 20; // Oversold level
|
||||||
|
|
||||||
**Strategy Settings:**
|
// Risk Management
|
||||||
- Symbol: XAUUSD
|
TakeProfitPips = 635; // Take profit in pips
|
||||||
- Period: H1 (2021.01.01 - 2025.04.11)
|
StopLossPips = 290; // Stop loss in pips
|
||||||
- Magic Number: 42
|
MaxLotSize = 0.1; // Maximum lot size
|
||||||
- Score Threshold: 5200
|
MaxDuration = 22; // Maximum trade duration in hours
|
||||||
- Slope Threshold: 93
|
RSIExitLevel = 57; // RSI level to exit
|
||||||
- Max Score: 7900.0
|
```
|
||||||
- Cooldown Minutes: 18
|
|
||||||
- Trade Cooldown Minutes: 24
|
**Test Balance Results:**
|
||||||
- EMA Time Frame: 16385
|
<div align="center">
|
||||||
- EMA Period: 64
|
<img src="RSIReversalAsianEURUSD/test-balance.jpg" alt="RSI Reversal Asian EUR/USD Test Balance" width="600"/>
|
||||||
- Cross Over Step: 950.0
|
</div>
|
||||||
- Slope Threshold Step: 635.0
|
|
||||||
- EMA Distance Step: 150.0
|
### 4. RSI CrossOver Reversal XAU/USD
|
||||||
- ATR Multiplier: 7.6
|
- **Strategy**: RSI crossover strategy for Gold trading
|
||||||
- Trailing Stop: 5.0
|
- **Key Features**:
|
||||||
- Max Crossover Trades: 4
|
- Uses RSI crossovers for entry and exit signals
|
||||||
- Max Drawdown: 10%
|
- Optimized for Gold market conditions
|
||||||
- Minimum Lot Size: 0.01
|
- Includes multiple timeframe analysis
|
||||||
- Max Time in Position: 9 hours
|
- Risk management features
|
||||||
- Trade Length Threshold: 98
|
|
||||||
- Reverse TP: 32
|
**Core Parameters:**
|
||||||
- Reverse Lot Size Multiplier: 15
|
```mql5
|
||||||
- Secondary Position Hold Time: 32
|
// RSI Settings
|
||||||
|
rsiPeriod = 19; // RSI period
|
||||||
**Performance Metrics (2021-2025):**
|
overboughtLevel = 93; // Overbought level
|
||||||
| Metric | Value |
|
oversoldLevel = 22; // Oversold level
|
||||||
|--------|-------|
|
|
||||||
| Total Net Profit | $388.52 |
|
// EMA Settings
|
||||||
| Gross Profit | $391.65 |
|
emaPeriod = 140; // EMA period
|
||||||
| Gross Loss | -$3.13 |
|
emaSlopeThreshold = 105; // EMA slope threshold
|
||||||
| Profit Factor | 125.13 |
|
emaDistanceThreshold = 165; // EMA distance threshold
|
||||||
| Recovery Factor | 11.66 |
|
|
||||||
| Expected Payoff | $0.72 |
|
// Risk Management
|
||||||
| Sharpe Ratio | 41.49 |
|
TrailingStop = 295; // Trailing stop in pips
|
||||||
| AHPR | 1.0006 (0.06%) |
|
```
|
||||||
| GHPR | 1.0006 (0.06%) |
|
|
||||||
|
**Test Balance Results:**
|
||||||
**Trade Statistics (2021-2025):**
|
<div align="center">
|
||||||
| Statistic | Value |
|
<img src="RSICrossOverReversalXAUUSD/test-balance.jpg" alt="RSI CrossOver Reversal XAU/USD Test Balance" width="600"/>
|
||||||
|-----------|-------|
|
</div>
|
||||||
| History Quality | 82% real ticks |
|
|
||||||
| Total Bars | 25,283 |
|
## Strategy Rationale
|
||||||
| Total Ticks | 165,999,507 |
|
|
||||||
| Balance Drawdown Absolute | $0.00 |
|
### RSI Reversal Strategy
|
||||||
| Equity Drawdown Absolute | $0.10 |
|
The RSI Reversal strategy is based on the principle that markets tend to revert to their mean after reaching extreme conditions. The strategy:
|
||||||
| Balance Drawdown Maximal | $0.69 (0.05%) |
|
- Enters trades when RSI reaches overbought/oversold levels
|
||||||
| Equity Drawdown Maximal | $33.32 (2.56%) |
|
- Uses Asian session timing to capitalize on specific market conditions
|
||||||
| Balance Drawdown Relative | 0.05% ($0.69) |
|
- Implements strict risk management to protect capital
|
||||||
| Equity Drawdown Relative | 2.92% ($30.23) |
|
- Takes advantage of mean reversion tendencies in currency pairs
|
||||||
|
|
||||||
**Balance Sheet (2021-2025):**
|
### RSI MidPoint Hijack Strategy
|
||||||

|
This advanced strategy combines multiple approaches:
|
||||||
|
- RSI Follow: Capitalizes on strong trends
|
||||||
|
- RSI Reverse: Takes advantage of market reversals
|
||||||
### 3. RSI Divergence Extrema AUDUSD
|
- EMA Cross: Provides additional confirmation signals
|
||||||
|
- Strategy locking: Protects profits during favorable conditions
|
||||||
A strategy that combines RSI divergence with extreme price points detection for enhanced market reversal signals.
|
- Cooldown periods: Prevents over-trading after losses
|
||||||
|
|
||||||
**Key Features:**
|
## Profitability Factors
|
||||||
- RSI divergence patterns detection
|
|
||||||
- Extreme price points identification
|
These EAs are designed to be profitable in the long run due to:
|
||||||
- Dynamic exit based on RSI thresholds
|
|
||||||
- Advanced risk management
|
1. **Risk Management**
|
||||||
|
- Strict stop loss implementation
|
||||||
**Strategy Settings:**
|
- Take profit targets
|
||||||
- Symbol: AUDUSD
|
- Spread monitoring
|
||||||
- Period: H1 (2021.01.01 - 2025.04.11)
|
- Position sizing control
|
||||||
- RSI Period: 14
|
|
||||||
- RSI Overbought: 70
|
2. **Market Timing**
|
||||||
- RSI Oversold: 30
|
- Session-based trading
|
||||||
- Base Lot Size: 0.01
|
- Time-specific entry and exit rules
|
||||||
- Exit Buy RSI Threshold: 60.0
|
- Avoidance of high volatility periods
|
||||||
- Exit Sell RSI Threshold: 40.0
|
|
||||||
- Bar Time Frame: 16385
|
3. **Strategy Diversification**
|
||||||
|
- Multiple entry and exit conditions
|
||||||
**Performance Metrics (2021-2025):**
|
- Different timeframes
|
||||||
| Metric | Value |
|
- Various technical indicators
|
||||||
|--------|-------|
|
|
||||||
| Total Net Profit | $141.61 |
|
4. **Adaptive Features**
|
||||||
| Gross Profit | $508.54 |
|
- Strategy locking during profitable periods
|
||||||
| Gross Loss | -$366.93 |
|
- Cooldown periods after losses
|
||||||
| Profit Factor | 1.39 |
|
- Spread-based trade filtering
|
||||||
| Recovery Factor | 3.37 |
|
|
||||||
| Expected Payoff | $0.59 |
|
## Usage
|
||||||
| Sharpe Ratio | 1.72 |
|
|
||||||
| AHPR | 1.0009 (0.09%) |
|
Each EA comes with configurable parameters that can be adjusted based on:
|
||||||
| GHPR | 1.0009 (0.09%) |
|
- Market conditions
|
||||||
|
- Risk tolerance
|
||||||
**Trade Statistics (2021-2025):**
|
- Trading style
|
||||||
| Statistic | Value |
|
- Account size
|
||||||
|-----------|-------|
|
|
||||||
| History Quality | 82% real ticks |
|
Please refer to the individual EA files for specific parameter descriptions and recommended settings.
|
||||||
| Total Bars | 26,604 |
|
|
||||||
| Total Ticks | 116,467,811 |
|
|
||||||
| Total Trades | 240 |
|
|
||||||
| Total Deals | 480 |
|
|
||||||
| Profit Trades | 158 (65.83%) |
|
|
||||||
| Loss Trades | 82 (34.17%) |
|
|
||||||
| Short Trades Won | 70.73% |
|
|
||||||
| Long Trades Won | 60.68% |
|
|
||||||
| Largest Profit Trade | $12.35 |
|
|
||||||
| Largest Loss Trade | -$18.76 |
|
|
||||||
| Average Profit Trade | $3.22 |
|
|
||||||
| Average Loss Trade | -$4.47 |
|
|
||||||
| Max Consecutive Wins | 11 ($35.96) |
|
|
||||||
| Max Consecutive Losses | 4 (-$26.61) |
|
|
||||||
|
|
||||||
**Drawdown Analysis (2021-2025):**
|
|
||||||
| Metric | Value |
|
|
||||||
|--------|-------|
|
|
||||||
| Balance Drawdown Absolute | $6.16 |
|
|
||||||
| Equity Drawdown Absolute | $14.13 |
|
|
||||||
| Balance Drawdown Maximal | $34.06 (4.50%) |
|
|
||||||
| Equity Drawdown Maximal | $42.06 (5.54%) |
|
|
||||||
| Balance Drawdown Relative | 4.55% ($32.84) |
|
|
||||||
| Equity Drawdown Relative | 5.54% ($42.06) |
|
|
||||||
|
|
||||||
**Balance Sheet (2021-2025):**
|
|
||||||

|
|
||||||
|
|
||||||
### 4. RSI Divergence Extrema EURUSD
|
|
||||||
|
|
||||||
A strategy that combines RSI divergence with extreme price points detection for enhanced market reversal signals on EURUSD.
|
|
||||||
|
|
||||||
**Key Features:**
|
|
||||||
- RSI divergence patterns detection
|
|
||||||
- Extreme price points identification
|
|
||||||
- Dynamic exit based on RSI thresholds
|
|
||||||
- Advanced risk management with hedging
|
|
||||||
- Stuck trade detection and management
|
|
||||||
|
|
||||||
**Strategy Settings:**
|
|
||||||
- Symbol: EURUSD
|
|
||||||
- Period: H6 (2021.01.01 - 2025.04.11)
|
|
||||||
- RSI Period: 14
|
|
||||||
- RSI Overbought: 71
|
|
||||||
- RSI Oversold: 33
|
|
||||||
- Base Lot Size: 0.01
|
|
||||||
- Exit Buy RSI Threshold: 60
|
|
||||||
- Exit Sell RSI Threshold: 40
|
|
||||||
- Bar Time Frame: 16390
|
|
||||||
- Extrema Expiry Bars: 45
|
|
||||||
- Stuck Trade Bars: 6
|
|
||||||
- Hedge Lot Multiplier: 6
|
|
||||||
|
|
||||||
**Performance Metrics (2021-2025):**
|
|
||||||
| Metric | Value |
|
|
||||||
|--------|-------|
|
|
||||||
| Total Net Profit | $510.13 |
|
|
||||||
| Gross Profit | $1,033.91 |
|
|
||||||
| Gross Loss | -$523.78 |
|
|
||||||
| Profit Factor | 1.97 |
|
|
||||||
| Recovery Factor | 2.87 |
|
|
||||||
| Expected Payoff | $4.15 |
|
|
||||||
| Sharpe Ratio | 2.80 |
|
|
||||||
| AHPR | 1.0053 (0.53%) |
|
|
||||||
| GHPR | 1.0050 (0.50%) |
|
|
||||||
|
|
||||||
**Trade Statistics (2021-2025):**
|
|
||||||
| Statistic | Value |
|
|
||||||
|-----------|-------|
|
|
||||||
| History Quality | 82% real ticks |
|
|
||||||
| Total Bars | 4,436 |
|
|
||||||
| Total Ticks | 107,013,176 |
|
|
||||||
| Total Trades | 123 |
|
|
||||||
| Total Deals | 246 |
|
|
||||||
| Profit Trades | 66 (53.66%) |
|
|
||||||
| Loss Trades | 57 (46.34%) |
|
|
||||||
| Short Trades Won | 69.49% |
|
|
||||||
| Long Trades Won | 39.06% |
|
|
||||||
| Largest Profit Trade | $76.90 |
|
|
||||||
| Largest Loss Trade | -$71.89 |
|
|
||||||
| Average Profit Trade | $15.67 |
|
|
||||||
| Average Loss Trade | -$9.19 |
|
|
||||||
| Max Consecutive Wins | 4 ($32.75) |
|
|
||||||
| Max Consecutive Losses | 3 (-$85.50) |
|
|
||||||
|
|
||||||
**Drawdown Analysis (2021-2025):**
|
|
||||||
| Metric | Value |
|
|
||||||
|--------|-------|
|
|
||||||
| Balance Drawdown Absolute | $0.00 |
|
|
||||||
| Equity Drawdown Absolute | $14.91 |
|
|
||||||
| Balance Drawdown Maximal | $85.50 (8.28%) |
|
|
||||||
| Equity Drawdown Maximal | $177.46 (16.45%) |
|
|
||||||
| Balance Drawdown Relative | 8.28% ($85.50) |
|
|
||||||
| Equity Drawdown Relative | 16.45% ($177.46) |
|
|
||||||
|
|
||||||
**Balance Sheet (2021-2025):**
|
|
||||||

|
|
||||||
|
|
||||||
### 5. RSI Reversal Asian AUDUSD
|
|
||||||
|
|
||||||
A strategy specifically designed for the Asian session on AUDUSD, using RSI reversals with optimized parameters for this market condition.
|
|
||||||
|
|
||||||
**Key Features:**
|
|
||||||
- RSI reversal patterns detection
|
|
||||||
- Asian session optimization
|
|
||||||
- Dynamic exit based on RSI thresholds
|
|
||||||
- Advanced position management
|
|
||||||
- Session-based trading rules
|
|
||||||
|
|
||||||
**Strategy Settings:**
|
|
||||||
- Symbol: AUDUSD
|
|
||||||
- Period: M15 (2021.01.01 - 2025.04.03)
|
|
||||||
- RSI Period: 14
|
|
||||||
- RSI Overbought: 67
|
|
||||||
- RSI Oversold: 17
|
|
||||||
- Take Profit: 253 pips
|
|
||||||
- Stop Loss: 429 pips
|
|
||||||
- Max Lot Size: 0.1
|
|
||||||
- Max Spread: 1000
|
|
||||||
- Max Duration: 81
|
|
||||||
- RSI Exit Level: 49
|
|
||||||
- Use Stop Loss: false
|
|
||||||
- Use Take Profit: true
|
|
||||||
- Use RSI Exit: true
|
|
||||||
|
|
||||||
**Performance Metrics (2021-2025):**
|
|
||||||
| Metric | Value |
|
|
||||||
|--------|-------|
|
|
||||||
| Total Net Profit | $1,521.11 |
|
|
||||||
| Gross Profit | $6,147.84 |
|
|
||||||
| Gross Loss | -$4,626.73 |
|
|
||||||
| Profit Factor | 1.33 |
|
|
||||||
| Recovery Factor | 4.30 |
|
|
||||||
| Expected Payoff | $2.32 |
|
|
||||||
| Sharpe Ratio | 2.14 |
|
|
||||||
| AHPR | 1.0022 (0.22%) |
|
|
||||||
| GHPR | 1.0019 (0.19%) |
|
|
||||||
|
|
||||||
**Trade Statistics (2021-2025):**
|
|
||||||
| Statistic | Value |
|
|
||||||
|-----------|-------|
|
|
||||||
| History Quality | 100% |
|
|
||||||
| Total Bars | 105,824 |
|
|
||||||
| Total Ticks | 6,215,660 |
|
|
||||||
| Total Trades | 657 |
|
|
||||||
| Total Deals | 1,314 |
|
|
||||||
| Profit Trades | 491 (74.73%) |
|
|
||||||
| Loss Trades | 166 (25.27%) |
|
|
||||||
| Short Trades Won | 75.52% |
|
|
||||||
| Long Trades Won | 61.11% |
|
|
||||||
| Largest Profit Trade | $24.20 |
|
|
||||||
| Largest Loss Trade | -$106.60 |
|
|
||||||
| Average Profit Trade | $12.52 |
|
|
||||||
| Average Loss Trade | -$27.87 |
|
|
||||||
| Max Consecutive Wins | 17 ($266.30) |
|
|
||||||
| Max Consecutive Losses | 4 (-$124.19) |
|
|
||||||
|
|
||||||
**Drawdown Analysis (2021-2025):**
|
|
||||||
| Metric | Value |
|
|
||||||
|--------|-------|
|
|
||||||
| Balance Drawdown Absolute | $158.27 |
|
|
||||||
| Equity Drawdown Absolute | $189.77 |
|
|
||||||
| Balance Drawdown Maximal | $302.68 (16.43%) |
|
|
||||||
| Equity Drawdown Maximal | $353.92 (20.63%) |
|
|
||||||
| Balance Drawdown Relative | 26.38% ($158.27) |
|
|
||||||
| Equity Drawdown Relative | 31.97% ($192.77) |
|
|
||||||
|
|
||||||
**Balance Sheet (2021-2025):**
|
|
||||||

|
|
||||||
|
|
||||||
### 6. RSI Reversal Asian EURUSD
|
|
||||||
|
|
||||||
A strategy specifically designed for the Asian session on EURUSD, using RSI reversals with optimized parameters for this market condition.
|
|
||||||
|
|
||||||
**Key Features:**
|
|
||||||
- RSI reversal patterns detection
|
|
||||||
- Asian session optimization
|
|
||||||
- Dynamic exit based on RSI thresholds
|
|
||||||
- Advanced position management
|
|
||||||
- Session-based trading rules
|
|
||||||
|
|
||||||
**Strategy Settings:**
|
|
||||||
- Symbol: EURUSD
|
|
||||||
- Period: M15 (2021.01.01 - 2025.04.03)
|
|
||||||
- RSI Period: 14
|
|
||||||
- RSI Overbought: 77
|
|
||||||
- RSI Oversold: 10
|
|
||||||
- Take Profit: 116 pips
|
|
||||||
- Stop Loss: 247 pips
|
|
||||||
- Max Lot Size: 0.1
|
|
||||||
- Max Spread: 1000
|
|
||||||
- Max Duration: 67
|
|
||||||
- RSI Exit Level: 40
|
|
||||||
- Use Stop Loss: true
|
|
||||||
- Use Take Profit: false
|
|
||||||
- Use RSI Exit: true
|
|
||||||
|
|
||||||
**Performance Metrics (2021-2025):**
|
|
||||||
| Metric | Value |
|
|
||||||
|--------|-------|
|
|
||||||
| Total Net Profit | $955.26 |
|
|
||||||
| Gross Profit | $1,961.62 |
|
|
||||||
| Gross Loss | -$1,006.36 |
|
|
||||||
| Profit Factor | 1.95 |
|
|
||||||
| Recovery Factor | 6.70 |
|
|
||||||
| Expected Payoff | $12.09 |
|
|
||||||
| Sharpe Ratio | 6.99 |
|
|
||||||
| AHPR | 1.0132 (1.32%) |
|
|
||||||
| GHPR | 1.0121 (1.21%) |
|
|
||||||
|
|
||||||
**Trade Statistics (2021-2025):**
|
|
||||||
| Statistic | Value |
|
|
||||||
|-----------|-------|
|
|
||||||
| History Quality | 100% |
|
|
||||||
| Total Bars | 105,824 |
|
|
||||||
| Total Ticks | 6,218,391 |
|
|
||||||
| Total Trades | 79 |
|
|
||||||
| Total Deals | 158 |
|
|
||||||
| Profit Trades | 40 (50.63%) |
|
|
||||||
| Loss Trades | 39 (49.37%) |
|
|
||||||
| Short Trades Won | 50.00% |
|
|
||||||
| Long Trades Won | 100.00% |
|
|
||||||
| Largest Profit Trade | $129.78 |
|
|
||||||
| Largest Loss Trade | -$30.90 |
|
|
||||||
| Average Profit Trade | $49.04 |
|
|
||||||
| Average Loss Trade | -$25.80 |
|
|
||||||
| Max Consecutive Wins | 5 ($223.98) |
|
|
||||||
| Max Consecutive Losses | 3 (-$79.60) |
|
|
||||||
|
|
||||||
**Drawdown Analysis (2021-2025):**
|
|
||||||
| Metric | Value |
|
|
||||||
|--------|-------|
|
|
||||||
| Balance Drawdown Absolute | $0.00 |
|
|
||||||
| Equity Drawdown Absolute | $2.51 |
|
|
||||||
| Balance Drawdown Maximal | $113.91 (7.03%) |
|
|
||||||
| Equity Drawdown Maximal | $142.61 (8.74%) |
|
|
||||||
| Balance Drawdown Relative | 13.81% ($98.24) |
|
|
||||||
| Equity Drawdown Relative | 16.97% ($122.14) |
|
|
||||||
|
|
||||||
**Balance Sheet (2021-2025):**
|
|
||||||

|
|
||||||
|
|
||||||
### 7. EMA Crossover BTC
|
|
||||||
|
|
||||||
A strategy specifically designed for Bitcoin (BTCUSD) using EMA crossovers with advanced scoring and position management.
|
|
||||||
|
|
||||||
**Key Features:**
|
|
||||||
- EMA crossover detection
|
|
||||||
- Advanced scoring system
|
|
||||||
- Trailing stop management
|
|
||||||
- Position scaling and reversal capabilities
|
|
||||||
- Dynamic distance thresholds
|
|
||||||
- Decay multiplier for trend strength
|
|
||||||
|
|
||||||
**Strategy Settings:**
|
|
||||||
- Symbol: BTCUSD
|
|
||||||
- Period: H1 (2021.01.01 - 2025.04.03)
|
|
||||||
- Magic Number: 42
|
|
||||||
- Score Threshold: 15000
|
|
||||||
- Slope Threshold: 3500
|
|
||||||
- Max Score: 25000
|
|
||||||
- Cooldown Minutes: 18
|
|
||||||
- Trade Cooldown Minutes: 44
|
|
||||||
- EMA Time Frame: 16385
|
|
||||||
- Delay Clamp Absolute: 5000
|
|
||||||
- EMA Period: 139
|
|
||||||
- Cross Over Step: 2500
|
|
||||||
- Slope Threshold Step: 2000
|
|
||||||
- EMA Distance Step: 500
|
|
||||||
- EMA Decay Step: 0
|
|
||||||
- Decay Multiplier: 0.08
|
|
||||||
- Distance Threshold: 7100
|
|
||||||
- ATR Multiplier: 3.9
|
|
||||||
- Trailing Stop: 10
|
|
||||||
- Apply Trailing Stop: true
|
|
||||||
- Max Crossover Trades: 14
|
|
||||||
- Max Drawdown: 10%
|
|
||||||
- Minimum Lot Size: 0.01
|
|
||||||
- Max Time in Position: 1 hour
|
|
||||||
- Trade Length Threshold: 31
|
|
||||||
- Reverse TP: 707
|
|
||||||
- Reverse Lot Size Multiplier: 4
|
|
||||||
- Secondary Position Hold Time: 75
|
|
||||||
|
|
||||||
**Performance Metrics (2021-2025):**
|
|
||||||
| Metric | Value |
|
|
||||||
|--------|-------|
|
|
||||||
| Total Net Profit | $632.96 |
|
|
||||||
| Gross Profit | $849.93 |
|
|
||||||
| Gross Loss | -$216.97 |
|
|
||||||
| Profit Factor | 3.92 |
|
|
||||||
| Recovery Factor | 7.47 |
|
|
||||||
| Expected Payoff | $0.58 |
|
|
||||||
| Sharpe Ratio | 7.57 |
|
|
||||||
| AHPR | 1.0007 (0.07%) |
|
|
||||||
| GHPR | 1.0007 (0.07%) |
|
|
||||||
|
|
||||||
**Trade Statistics (2021-2025):**
|
|
||||||
| Statistic | Value |
|
|
||||||
|-----------|-------|
|
|
||||||
| History Quality | 98% |
|
|
||||||
| Total Bars | 35,791 |
|
|
||||||
| Total Ticks | 8,380,510 |
|
|
||||||
| Balance Drawdown Absolute | $0.00 |
|
|
||||||
| Equity Drawdown Absolute | $2.72 |
|
|
||||||
| Balance Drawdown Maximal | $41.94 (3.52%) |
|
|
||||||
| Equity Drawdown Maximal | $84.72 (7.13%) |
|
|
||||||
| Balance Drawdown Relative | 3.52% ($41.94) |
|
|
||||||
| Equity Drawdown Relative | 7.13% ($84.72) |
|
|
||||||
|
|
||||||
**Balance Sheet (2021-2025):**
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
### 8. Smart RSI BTC
|
|
||||||
|
|
||||||
A strategy that implements a smart RSI-based trading system specifically optimized for Bitcoin trading.
|
|
||||||
|
|
||||||
**Key Features:**
|
|
||||||
- Advanced RSI-based entry and exit signals
|
|
||||||
- Dynamic position sizing
|
|
||||||
- Risk management through stop loss and take profit levels
|
|
||||||
- Optimized for Bitcoin market conditions
|
|
||||||
|
|
||||||
**Strategy Settings:**
|
|
||||||
- Symbol: BTCUSD
|
|
||||||
- Period: H1
|
|
||||||
- RSI Period: 14
|
|
||||||
- RSI Overbought: 70
|
|
||||||
- RSI Oversold: 30
|
|
||||||
- Base Lot Size: 0.01
|
|
||||||
- Max Spread: 50
|
|
||||||
- Max Risk Percent: 2%
|
|
||||||
- Max Drawdown Percent: 10%
|
|
||||||
- Max Consecutive Losses: 3
|
|
||||||
- Max Lot Size: 0.1
|
|
||||||
|
|
||||||
**Performance Metrics:**
|
|
||||||
| Metric | Value |
|
|
||||||
|--------|-------|
|
|
||||||
| Total Net Profit | $1,344.74 |
|
|
||||||
| Gross Profit | $4,410.51 |
|
|
||||||
| Gross Loss | -$3,065.77 |
|
|
||||||
| Profit Factor | 1.44 |
|
|
||||||
| Recovery Factor | 4.91 |
|
|
||||||
| Expected Payoff | $4.87 |
|
|
||||||
| Sharpe Ratio | 1.69 |
|
|
||||||
| AHPR | 1.0033 (0.33%) |
|
|
||||||
| GHPR | 1.0031 (0.31%) |
|
|
||||||
|
|
||||||
**Trade Statistics:**
|
|
||||||
| Statistic | Value |
|
|
||||||
|-----------|-------|
|
|
||||||
| Total Trades | 276 |
|
|
||||||
| Total Deals | 552 |
|
|
||||||
| Profit Trades | 81 (29.35%) |
|
|
||||||
| Loss Trades | 195 (70.65%) |
|
|
||||||
| Short Trades Won | 26.28% |
|
|
||||||
| Long Trades Won | 32.37% |
|
|
||||||
| Largest Profit Trade | $144.46 |
|
|
||||||
| Largest Loss Trade | -$46.66 |
|
|
||||||
| Average Profit Trade | $54.45 |
|
|
||||||
| Average Loss Trade | -$15.72 |
|
|
||||||
| Max Consecutive Wins | 3 ($179.71) |
|
|
||||||
| Max Consecutive Losses | 15 (-$159.89) |
|
|
||||||
|
|
||||||
**Drawdown Analysis:**
|
|
||||||
| Metric | Value |
|
|
||||||
|--------|-------|
|
|
||||||
| Balance Drawdown Absolute | $18.62 |
|
|
||||||
| Equity Drawdown Absolute | $19.45 |
|
|
||||||
| Balance Drawdown Maximal | $231.79 (10.21%) |
|
|
||||||
| Equity Drawdown Maximal | $273.75 (11.93%) |
|
|
||||||
| Balance Drawdown Relative | 13.47% ($210.14) |
|
|
||||||
| Equity Drawdown Relative | 15.85% ($250.78) |
|
|
||||||
|
|
||||||
**Balance Sheet:**
|
|
||||||

|
|
||||||
|
|
||||||
### 9. RSI MidPoint Hijack
|
|
||||||
|
|
||||||
A strategy that combines RSI analysis with midpoint-based entry and exit signals for enhanced trading performance.
|
|
||||||
|
|
||||||
**Key Features:**
|
|
||||||
- RSI-based trend analysis
|
|
||||||
- Midpoint-based entry and exit signals
|
|
||||||
- Dynamic position sizing
|
|
||||||
- Advanced risk management
|
|
||||||
|
|
||||||
**Strategy Settings:**
|
|
||||||
- Symbol: XAUUSD
|
|
||||||
- Period: H1
|
|
||||||
- RSI Period: 14
|
|
||||||
- RSI Overbought: 70
|
|
||||||
- RSI Oversold: 30
|
|
||||||
- Base Lot Size: 0.01
|
|
||||||
- Max Spread: 50
|
|
||||||
- Max Risk Percent: 2%
|
|
||||||
- Max Drawdown Percent: 10%
|
|
||||||
- Max Consecutive Losses: 3
|
|
||||||
- Max Lot Size: 0.1
|
|
||||||
|
|
||||||
**Performance Metrics:**
|
|
||||||
| Metric | Value |
|
|
||||||
|--------|-------|
|
|
||||||
| Total Net Profit | $1,344.74 |
|
|
||||||
| Gross Profit | $4,410.51 |
|
|
||||||
| Gross Loss | -$3,065.77 |
|
|
||||||
| Profit Factor | 1.44 |
|
|
||||||
| Recovery Factor | 4.91 |
|
|
||||||
| Expected Payoff | $4.87 |
|
|
||||||
| Sharpe Ratio | 1.69 |
|
|
||||||
| AHPR | 1.0033 (0.33%) |
|
|
||||||
| GHPR | 1.0031 (0.31%) |
|
|
||||||
|
|
||||||
**Trade Statistics:**
|
|
||||||
| Statistic | Value |
|
|
||||||
|-----------|-------|
|
|
||||||
| Total Trades | 276 |
|
|
||||||
| Total Deals | 552 |
|
|
||||||
| Profit Trades | 81 (29.35%) |
|
|
||||||
| Loss Trades | 195 (70.65%) |
|
|
||||||
| Short Trades Won | 26.28% |
|
|
||||||
| Long Trades Won | 32.37% |
|
|
||||||
| Largest Profit Trade | $144.46 |
|
|
||||||
| Largest Loss Trade | -$46.66 |
|
|
||||||
| Average Profit Trade | $54.45 |
|
|
||||||
| Average Loss Trade | -$15.72 |
|
|
||||||
| Max Consecutive Wins | 3 ($179.71) |
|
|
||||||
| Max Consecutive Losses | 15 (-$159.89) |
|
|
||||||
|
|
||||||
**Drawdown Analysis:**
|
|
||||||
| Metric | Value |
|
|
||||||
|--------|-------|
|
|
||||||
| Balance Drawdown Absolute | $18.62 |
|
|
||||||
| Equity Drawdown Absolute | $19.45 |
|
|
||||||
| Balance Drawdown Maximal | $231.79 (10.21%) |
|
|
||||||
| Equity Drawdown Maximal | $273.75 (11.93%) |
|
|
||||||
| Balance Drawdown Relative | 13.47% ($210.14) |
|
|
||||||
| Equity Drawdown Relative | 15.85% ($250.78) |
|
|
||||||
|
|
||||||
**Balance Sheet:**
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
## Technical Details
|
|
||||||
Each EA is implemented in MQL5 and includes:
|
|
||||||
- Custom strategy implementation
|
|
||||||
- Entry/exit logic
|
|
||||||
- Risk management parameters
|
|
||||||
- Position sizing rules
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
- MetaTrader 5 platform
|
|
||||||
- MQL5 programming language support
|
|
||||||
- Sufficient historical data for backtesting
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
1. Copy the desired EA file to your MT5 Experts folder
|
|
||||||
2. Compile the EA in MetaEditor
|
|
||||||
3. Attach the EA to a chart with appropriate settings
|
|
||||||
|
|
||||||
## Disclaimer
|
## Disclaimer
|
||||||
These Expert Advisors are for educational and research purposes only. Past performance does not guarantee future results. Always test thoroughly before using in live trading.
|
|
||||||
|
Trading involves substantial risk of loss. These EAs are provided for educational purposes only. Always test thoroughly on a demo account before using with real money. Past performance does not guarantee future results.
|
||||||
|
|||||||
@@ -0,0 +1,315 @@
|
|||||||
|
// Input Parameters
|
||||||
|
#include <Trade\Trade.mqh>
|
||||||
|
|
||||||
|
input group "Trade Management"
|
||||||
|
input int MagicNumber = 7;
|
||||||
|
input int rsiPeriod = 19; // RSI period
|
||||||
|
input int overboughtLevel = 93; // Overbought level (RSI > 70 for sell)
|
||||||
|
input int oversoldLevel = 22; // Oversold level (RSI < 30 for buy)
|
||||||
|
input double entryRSIBuySpread = 0;
|
||||||
|
input double entryRSISellSpread = 0;
|
||||||
|
input double lotSize = 0.01; // Trade lot size
|
||||||
|
input int slippage = 3; // Slippage for orders
|
||||||
|
input int cooldownSeconds = 209; // Cooldown period in seconds
|
||||||
|
input ENUM_TIMEFRAMES TimeFrame1 = PERIOD_M1; // RSI Timeframe
|
||||||
|
input ENUM_TIMEFRAMES TimeFrame2 = PERIOD_M1; // EMA Timeframe
|
||||||
|
input ENUM_TIMEFRAMES BarTimeFrame = PERIOD_M12; // EMA Timeframe
|
||||||
|
input int emaPeriod = 140; // EMA period
|
||||||
|
input double emaSlopeThreshold = 105; // EMA slope threshold for trend strength
|
||||||
|
input double exitBuyRSI = 86;
|
||||||
|
input double exitSellRSI = 10;
|
||||||
|
input double TrailingStop = 295;
|
||||||
|
input double emaDistanceThreshold = 165;
|
||||||
|
input int tradingHourOneBegin = 24;
|
||||||
|
input int tradingHourOneEnd = 22;
|
||||||
|
input int tradingHourTwoBegin = 6;
|
||||||
|
input int tradingHourTwoEnd = 19;
|
||||||
|
datetime bartime;
|
||||||
|
// RSI Handle
|
||||||
|
int rsiHandle;
|
||||||
|
|
||||||
|
input bool Sunday =false; // Sunday
|
||||||
|
input bool Monday =false; // Monday
|
||||||
|
input bool Tuesday =true; // Tuesday
|
||||||
|
input bool Wednesday=true; // Wednesday
|
||||||
|
input bool Thursday =true; // Thursday
|
||||||
|
input bool Friday =false; // Friday
|
||||||
|
input bool Saturday =false; // Saturday
|
||||||
|
|
||||||
|
bool WeekDays[7];
|
||||||
|
|
||||||
|
void WeekDays_Init()
|
||||||
|
{
|
||||||
|
WeekDays[0]=Sunday;
|
||||||
|
WeekDays[1]=Monday;
|
||||||
|
WeekDays[2]=Tuesday;
|
||||||
|
WeekDays[3]=Wednesday;
|
||||||
|
WeekDays[4]=Thursday;
|
||||||
|
WeekDays[5]=Friday;
|
||||||
|
WeekDays[6]=Saturday;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WeekDays_Check(datetime aTime)
|
||||||
|
{
|
||||||
|
MqlDateTime stm;
|
||||||
|
TimeToStruct(aTime,stm);
|
||||||
|
return(WeekDays[stm.day_of_week]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// EMA Handle
|
||||||
|
int emaHandle;
|
||||||
|
double previousRSIDef = 0;
|
||||||
|
// Create CTrade object for executing trades
|
||||||
|
CTrade trade;
|
||||||
|
|
||||||
|
// Track the last trade time
|
||||||
|
datetime lastTradeTime = 0;
|
||||||
|
|
||||||
|
void OnInit() {
|
||||||
|
WeekDays_Init();
|
||||||
|
|
||||||
|
// Create RSI handle
|
||||||
|
rsiHandle = iRSI(_Symbol, TimeFrame1, rsiPeriod, PRICE_CLOSE);
|
||||||
|
if (rsiHandle == INVALID_HANDLE) {
|
||||||
|
Print("Error creating RSI handle: ", GetLastError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create EMA handle
|
||||||
|
emaHandle = iMA(_Symbol, TimeFrame2, emaPeriod, 0, MODE_EMA, PRICE_CLOSE);
|
||||||
|
if (emaHandle == INVALID_HANDLE) {
|
||||||
|
Print("Error creating EMA handle: ", GetLastError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialization successful
|
||||||
|
Print("RSI and EMA Reversal Strategy Initialized.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnTick() {
|
||||||
|
if(bartime==iTime(_Symbol,BarTimeFrame,0))return;
|
||||||
|
bartime=iTime(_Symbol,BarTimeFrame,0);
|
||||||
|
|
||||||
|
// Check if RSI data is available
|
||||||
|
double rsi[];
|
||||||
|
if (CopyBuffer(rsiHandle, 0, 0, 2, rsi) <= 0) {
|
||||||
|
Print("Error copying RSI data: ", GetLastError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if EMA data is available
|
||||||
|
double ema[];
|
||||||
|
if (CopyBuffer(emaHandle, 0, 0, 2, ema) <= 0) {
|
||||||
|
Print("Error copying EMA data: ", GetLastError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the current time
|
||||||
|
datetime currentTime = TimeCurrent();
|
||||||
|
|
||||||
|
|
||||||
|
int currentHour = TimeHour(TimeCurrent());
|
||||||
|
|
||||||
|
if(!WeekDays_Check(TimeTradeServer())) {
|
||||||
|
Close_Position_MN(MagicNumber);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(currentHour < tradingHourOneEnd && currentHour > tradingHourOneBegin || currentHour < tradingHourTwoEnd && currentHour > tradingHourTwoBegin))
|
||||||
|
{
|
||||||
|
|
||||||
|
Close_Position_MN(MagicNumber);
|
||||||
|
return; // Prevent further trading during this time
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Ensure there is at least one position
|
||||||
|
bool hasPosition = (PositionsTotal() > 0);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Get the current and previous RSI values
|
||||||
|
double currentRSI = rsi[0];
|
||||||
|
double previousRSI = rsi[1];
|
||||||
|
|
||||||
|
if(previousRSIDef == 0) {
|
||||||
|
previousRSIDef = currentRSI;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the current and previous EMA values
|
||||||
|
double currentEMA = ema[0];
|
||||||
|
double previousEMA = ema[1];
|
||||||
|
|
||||||
|
// Calculate the EMA slope (difference between current and previous EMA values)
|
||||||
|
double emaSlope = (currentEMA - previousEMA) * 100;
|
||||||
|
Print(emaSlope);
|
||||||
|
|
||||||
|
double closeCurr = iClose(Symbol(), Period(), 0); // Close of current bar
|
||||||
|
// ** NEW CODE: Calculate distance to EMA and adjust score **
|
||||||
|
double priceToEmaDistance = (closeCurr - currentEMA) * 10; // Distance between the current price and the EMA
|
||||||
|
Print("priceToEmaDistance");
|
||||||
|
Print(priceToEmaDistance);
|
||||||
|
|
||||||
|
|
||||||
|
// Determine if there are existing buy or sell positions
|
||||||
|
bool isBuyPosition = false;
|
||||||
|
bool isSellPosition = false;
|
||||||
|
if (hasPosition) {
|
||||||
|
if (PositionSelect(_Symbol)) {
|
||||||
|
int positionType = PositionGetInteger(POSITION_TYPE);
|
||||||
|
if (positionType == POSITION_TYPE_BUY) {
|
||||||
|
isBuyPosition = true;
|
||||||
|
} else if (positionType == POSITION_TYPE_SELL) {
|
||||||
|
isSellPosition = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ApplyTrailingStop();
|
||||||
|
|
||||||
|
// Check if the cooldown period has elapsed since the last trade
|
||||||
|
bool cooldownPassed = (currentTime - lastTradeTime) >= cooldownSeconds;
|
||||||
|
|
||||||
|
// Check if EMA slope is above the threshold (indicating strong trend)
|
||||||
|
bool isTrendStrong = MathAbs(emaSlope) > emaSlopeThreshold || MathAbs(priceToEmaDistance) > emaDistanceThreshold;
|
||||||
|
|
||||||
|
// Close trade logic when RSI crosses 50
|
||||||
|
if (isBuyPosition && currentRSI > exitBuyRSI) {
|
||||||
|
// Close buy position
|
||||||
|
Close_Position_MN(MagicNumber);
|
||||||
|
lastTradeTime = currentTime; // Update last trade time
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSellPosition && currentRSI < exitSellRSI) {
|
||||||
|
Close_Position_MN(MagicNumber);
|
||||||
|
lastTradeTime = currentTime; // Update last trade time
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// If the EMA slope is strong, do not place new trades
|
||||||
|
if (isTrendStrong) {
|
||||||
|
Close_Position_MN(MagicNumber);
|
||||||
|
lastTradeTime = currentTime; // Update last trade time
|
||||||
|
Print("Strong trend detected (EMA slope), skipping new trade.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SELL logic (RSI crosses over the overbought level)
|
||||||
|
if (currentRSI < overboughtLevel - entryRSISellSpread && previousRSIDef >= overboughtLevel && !isSellPosition && !hasPosition && cooldownPassed) {
|
||||||
|
trade.SetExpertMagicNumber(MagicNumber);
|
||||||
|
if (trade.Sell(lotSize, _Symbol, 0, 0, "Sell Order")) {
|
||||||
|
Print("Sell order placed.");
|
||||||
|
lastTradeTime = currentTime; // Update last trade time
|
||||||
|
} else {
|
||||||
|
Print("Error placing sell order: ", GetLastError());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BUY logic (RSI crosses below the oversold level)
|
||||||
|
if (currentRSI > oversoldLevel + entryRSIBuySpread && previousRSIDef <= oversoldLevel && !isBuyPosition && !hasPosition && cooldownPassed) {
|
||||||
|
trade.SetExpertMagicNumber(MagicNumber);
|
||||||
|
if (trade.Buy(lotSize, _Symbol, 0, 0, "Buy Order")) {
|
||||||
|
Print("Buy order placed.");
|
||||||
|
lastTradeTime = currentTime; // Update last trade time
|
||||||
|
} else {
|
||||||
|
Print("Error placing buy order: ", GetLastError());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
previousRSIDef = currentRSI;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnDeinit(const int reason) {
|
||||||
|
// Release RSI and EMA handles on deinitialization
|
||||||
|
if (rsiHandle != INVALID_HANDLE) {
|
||||||
|
IndicatorRelease(rsiHandle);
|
||||||
|
Print("RSI handle released.");
|
||||||
|
}
|
||||||
|
if (emaHandle != INVALID_HANDLE) {
|
||||||
|
IndicatorRelease(emaHandle);
|
||||||
|
Print("EMA handle released.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Close_Position_MN(ulong magicNumber)
|
||||||
|
{
|
||||||
|
int total = PositionsTotal();
|
||||||
|
for(int i = total - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
ulong ticket = PositionGetTicket(i);
|
||||||
|
|
||||||
|
// Use PositionSelect by symbol instead of ticket
|
||||||
|
string symbol = PositionGetSymbol(i);
|
||||||
|
if(PositionSelect(symbol))
|
||||||
|
{
|
||||||
|
if (PositionGetInteger(POSITION_MAGIC) == magicNumber && PositionGetInteger(POSITION_TICKET) == ticket)
|
||||||
|
{
|
||||||
|
if(symbol == _Symbol) // Verify the symbol
|
||||||
|
{
|
||||||
|
Print("MN " + magicNumber);
|
||||||
|
trade.PositionClose(ticket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int errorCode = GetLastError();
|
||||||
|
Print("aaaa PositionSelect failed with error code: ", errorCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApplyTrailingStop()
|
||||||
|
{
|
||||||
|
Print("Scanning for trailing stop");
|
||||||
|
for(int i=PositionsTotal()-1; i>=0; i--)
|
||||||
|
{
|
||||||
|
string symbol = PositionGetSymbol(i);
|
||||||
|
ulong PositionTicket = PositionGetTicket(i);
|
||||||
|
long trade_type = PositionGetInteger(POSITION_TYPE);
|
||||||
|
|
||||||
|
if(!PositionGetInteger(POSITION_MAGIC) == MagicNumber) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double POINT = SymbolInfoDouble( symbol, SYMBOL_POINT );
|
||||||
|
int DIGIT = (int) SymbolInfoInteger( symbol, SYMBOL_DIGITS );
|
||||||
|
|
||||||
|
|
||||||
|
if(trade_type == 0)
|
||||||
|
{
|
||||||
|
double Bid = NormalizeDouble(SymbolInfoDouble(symbol,SYMBOL_BID),DIGIT);
|
||||||
|
|
||||||
|
if(Bid-PositionGetDouble(POSITION_PRICE_OPEN) > NormalizeDouble(POINT * TrailingStop,DIGIT))
|
||||||
|
{
|
||||||
|
if(PositionGetDouble(POSITION_SL) < NormalizeDouble(Bid - POINT * TrailingStop,DIGIT))
|
||||||
|
{
|
||||||
|
trade.PositionModify(PositionTicket,NormalizeDouble(Bid - POINT * TrailingStop,DIGIT),PositionGetDouble(POSITION_TP));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if(trade_type == 1)
|
||||||
|
{
|
||||||
|
double Ask = NormalizeDouble(SymbolInfoDouble(symbol,SYMBOL_ASK),DIGIT);
|
||||||
|
|
||||||
|
if((PositionGetDouble(POSITION_PRICE_OPEN) - Ask) > NormalizeDouble( POINT * TrailingStop,DIGIT))
|
||||||
|
{
|
||||||
|
if((PositionGetDouble(POSITION_SL) > NormalizeDouble(Ask + POINT * TrailingStop,DIGIT)) || (PositionGetDouble(POSITION_SL)==0))
|
||||||
|
{
|
||||||
|
trade.PositionModify(PositionTicket,NormalizeDouble(Ask + POINT * TrailingStop,DIGIT),PositionGetDouble(POSITION_TP));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int TimeHour(datetime when=0){ if(when == 0) when = TimeCurrent();
|
||||||
|
return when / 3600 % 24;
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 233 KiB |
@@ -1,347 +0,0 @@
|
|||||||
//+------------------------------------------------------------------+
|
|
||||||
//| RSIDivergenceRebound.mq5 |
|
|
||||||
//| Copyright 2024, MetaQuotes Ltd. |
|
|
||||||
//| https://www.mql5.com |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
#property copyright "Copyright 2024, MetaQuotes Ltd."
|
|
||||||
#property link "https://www.mql5.com"
|
|
||||||
#property version "1.00"
|
|
||||||
#property strict
|
|
||||||
|
|
||||||
#include <Trade\Trade.mqh> // Include CTrade class
|
|
||||||
|
|
||||||
// Input Parameters
|
|
||||||
input int RSI_Period = 14; // RSI Period
|
|
||||||
input int RSI_Overbought = 70; // RSI Overbought Level
|
|
||||||
input int RSI_Oversold = 30; // RSI Oversold Level
|
|
||||||
input double BaseLotSize = 0.01; // Base Lot Size
|
|
||||||
input ENUM_TIMEFRAMES BarTimeFrame = PERIOD_H1; // Timeframe for bar updates
|
|
||||||
input double ExitBuyRSIThreshold = 60; // RSI level to exit buy positions
|
|
||||||
input double ExitSellRSIThreshold = 40; // RSI level to exit sell positions
|
|
||||||
|
|
||||||
// Global Variables
|
|
||||||
int rsiHandle; // RSI indicator handle
|
|
||||||
CTrade trade; // Trade object
|
|
||||||
datetime lastBarTime = 0; // Last bar time
|
|
||||||
double RSILastThree = 0; // Third last RSI value
|
|
||||||
double RSILastTwo = 0; // Second last RSI value
|
|
||||||
double RSILast = 0; // Last RSI value
|
|
||||||
bool hasFirstExtrema = false; // Flag for first extrema
|
|
||||||
bool hasSecondExtrema = false; // Flag for second extrema
|
|
||||||
bool hasThirdExtrema = false; // Flag for third extrema
|
|
||||||
bool isOverboughtExtrema = false; // Flag for extrema type
|
|
||||||
double priceFirstExtrema = 0; // Price at first extrema
|
|
||||||
double rsiFirstExtrema = 0; // RSI at first extrema
|
|
||||||
double priceSecondExtrema = 0; // Price at second extrema
|
|
||||||
double rsiSecondExtrema = 0; // RSI at second extrema
|
|
||||||
double priceThirdExtrema = 0; // Price at third extrema
|
|
||||||
double rsiThirdExtrema = 0; // RSI at third extrema
|
|
||||||
string extremaPrefix = "Ext_"; // Prefix for extrema objects
|
|
||||||
datetime firstExtremaTime = 0; // Time of first extrema
|
|
||||||
datetime secondExtremaTime = 0; // Time of second extrema
|
|
||||||
datetime thirdExtremaTime = 0; // Time of third extrema
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Draw extrema point |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void DrawExtremaPoint(string name, datetime time, double price, color clr, int shape, string label)
|
|
||||||
{
|
|
||||||
// Create the point
|
|
||||||
ObjectCreate(0, name, OBJ_ARROW, 0, time, price);
|
|
||||||
ObjectSetInteger(0, name, OBJPROP_ARROWCODE, shape);
|
|
||||||
ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
|
|
||||||
ObjectSetInteger(0, name, OBJPROP_WIDTH, 2);
|
|
||||||
ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
|
|
||||||
ObjectSetInteger(0, name, OBJPROP_HIDDEN, false);
|
|
||||||
ObjectSetInteger(0, name, OBJPROP_BACK, true);
|
|
||||||
|
|
||||||
// Add label
|
|
||||||
string labelName = name + "_Label";
|
|
||||||
ObjectCreate(0, labelName, OBJ_TEXT, 0, time, price);
|
|
||||||
ObjectSetString(0, labelName, OBJPROP_TEXT, label);
|
|
||||||
ObjectSetInteger(0, labelName, OBJPROP_COLOR, clr);
|
|
||||||
ObjectSetInteger(0, labelName, OBJPROP_FONTSIZE, 8);
|
|
||||||
ObjectSetInteger(0, labelName, OBJPROP_SELECTABLE, false);
|
|
||||||
ObjectSetInteger(0, labelName, OBJPROP_HIDDEN, false);
|
|
||||||
ObjectSetInteger(0, labelName, OBJPROP_BACK, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Clean up extrema objects |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void CleanupExtremaObjects()
|
|
||||||
{
|
|
||||||
for(int i = ObjectsTotal(0, 0, -1) - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
string name = ObjectName(0, i, 0, -1);
|
|
||||||
if(StringFind(name, extremaPrefix) == 0)
|
|
||||||
{
|
|
||||||
ObjectDelete(0, name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Expert initialization function |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
int OnInit()
|
|
||||||
{
|
|
||||||
// Initialize RSI indicator
|
|
||||||
rsiHandle = iRSI(_Symbol, BarTimeFrame, RSI_Period, PRICE_CLOSE);
|
|
||||||
|
|
||||||
if(rsiHandle == INVALID_HANDLE)
|
|
||||||
{
|
|
||||||
Print("Error creating RSI indicator");
|
|
||||||
return(INIT_FAILED);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize trade object
|
|
||||||
trade.SetExpertMagicNumber(123456);
|
|
||||||
|
|
||||||
Print("RSI Divergence Rebound Strategy Initialized");
|
|
||||||
Print("RSI Period: ", RSI_Period);
|
|
||||||
Print("Overbought Level: ", RSI_Overbought);
|
|
||||||
Print("Oversold Level: ", RSI_Oversold);
|
|
||||||
|
|
||||||
// Clean up any existing extrema objects
|
|
||||||
CleanupExtremaObjects();
|
|
||||||
|
|
||||||
return(INIT_SUCCEEDED);
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Expert deinitialization function |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void OnDeinit(const int reason)
|
|
||||||
{
|
|
||||||
// Clean up extrema objects
|
|
||||||
CleanupExtremaObjects();
|
|
||||||
|
|
||||||
IndicatorRelease(rsiHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Check for local extrema in RSI |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
bool IsLocalExtrema(double rsi1, double rsi2, double rsi3, bool& isMaxima)
|
|
||||||
{
|
|
||||||
if(rsi2 > rsi1 && rsi2 > rsi3)
|
|
||||||
{
|
|
||||||
isMaxima = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if(rsi2 < rsi1 && rsi2 < rsi3)
|
|
||||||
{
|
|
||||||
isMaxima = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Check for divergence patterns |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
bool CheckDivergence(double price1, double rsi1, double price2, double rsi2, bool isOverbought)
|
|
||||||
{
|
|
||||||
if(isOverbought)
|
|
||||||
{
|
|
||||||
// Bearish divergence (price makes higher high, RSI makes lower high)
|
|
||||||
if(price2 > price1 && rsi2 < rsi1)
|
|
||||||
return true;
|
|
||||||
// Hidden bearish divergence (price makes lower high, RSI makes higher high)
|
|
||||||
if(price2 < price1 && rsi2 > rsi1)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Bullish divergence (price makes lower low, RSI makes higher low)
|
|
||||||
if(price2 < price1 && rsi2 > rsi1)
|
|
||||||
return true;
|
|
||||||
// Hidden bullish divergence (price makes higher low, RSI makes lower low)
|
|
||||||
if(price2 > price1 && rsi2 < rsi1)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Check if market is open |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
bool IsMarketOpen()
|
|
||||||
{
|
|
||||||
MqlDateTime dt;
|
|
||||||
TimeCurrent(dt);
|
|
||||||
|
|
||||||
// Check if it's a weekend
|
|
||||||
if(dt.day_of_week == 0 || dt.day_of_week == 6)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Check if it's within trading hours (assuming 24/5 market)
|
|
||||||
// You can modify these hours based on your broker's trading hours
|
|
||||||
int hour = dt.hour;
|
|
||||||
int minute = dt.min;
|
|
||||||
|
|
||||||
// Market is open 24/5 except weekends
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Expert tick function |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void OnTick()
|
|
||||||
{
|
|
||||||
// Check if market is open
|
|
||||||
if(!IsMarketOpen())
|
|
||||||
{
|
|
||||||
Print("Market is closed - resetting extrema");
|
|
||||||
ResetExtrema();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for new bar
|
|
||||||
datetime currentBarTime = iTime(_Symbol, BarTimeFrame, 0);
|
|
||||||
if(currentBarTime == lastBarTime)
|
|
||||||
return;
|
|
||||||
lastBarTime = currentBarTime;
|
|
||||||
|
|
||||||
// Get current RSI value
|
|
||||||
double rsiBuffer[];
|
|
||||||
ArraySetAsSeries(rsiBuffer, true);
|
|
||||||
if(CopyBuffer(rsiHandle, 0, 0, 1, rsiBuffer) != 1)
|
|
||||||
{
|
|
||||||
Print("Error copying RSI buffer");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update RSI queue
|
|
||||||
RSILastThree = RSILastTwo;
|
|
||||||
RSILastTwo = RSILast;
|
|
||||||
RSILast = rsiBuffer[0];
|
|
||||||
|
|
||||||
// Check if we have enough RSI values
|
|
||||||
if(RSILastThree == 0 || RSILastTwo == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Check for local extrema
|
|
||||||
bool isMaxima;
|
|
||||||
if(IsLocalExtrema(RSILastThree, RSILastTwo, RSILast, isMaxima))
|
|
||||||
{
|
|
||||||
// First extrema (must be overbought/oversold)
|
|
||||||
if(!hasFirstExtrema)
|
|
||||||
{
|
|
||||||
if((isMaxima && RSILastTwo >= RSI_Overbought) || (!isMaxima && RSILastTwo <= RSI_Oversold))
|
|
||||||
{
|
|
||||||
hasFirstExtrema = true;
|
|
||||||
isOverboughtExtrema = isMaxima;
|
|
||||||
priceFirstExtrema = iClose(_Symbol, BarTimeFrame, 1);
|
|
||||||
rsiFirstExtrema = RSILastTwo;
|
|
||||||
firstExtremaTime = iTime(_Symbol, BarTimeFrame, 1);
|
|
||||||
|
|
||||||
// Draw first extrema
|
|
||||||
string firstExtremaName = extremaPrefix + "First_" + TimeToString(firstExtremaTime);
|
|
||||||
DrawExtremaPoint(firstExtremaName, firstExtremaTime, priceFirstExtrema,
|
|
||||||
isMaxima ? clrRed : clrGreen, 234, "1st " + (isMaxima ? "OB" : "OS"));
|
|
||||||
|
|
||||||
Print("First extrema detected - Type: ", isMaxima ? "Overbought" : "Oversold",
|
|
||||||
", RSI: ", rsiFirstExtrema, ", Price: ", priceFirstExtrema);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Second extrema (check for divergence)
|
|
||||||
else if(!hasSecondExtrema)
|
|
||||||
{
|
|
||||||
priceSecondExtrema = iClose(_Symbol, BarTimeFrame, 1);
|
|
||||||
rsiSecondExtrema = RSILastTwo;
|
|
||||||
secondExtremaTime = iTime(_Symbol, BarTimeFrame, 1);
|
|
||||||
|
|
||||||
if(CheckDivergence(priceFirstExtrema, rsiFirstExtrema, priceSecondExtrema, rsiSecondExtrema, isOverboughtExtrema))
|
|
||||||
{
|
|
||||||
hasSecondExtrema = true;
|
|
||||||
|
|
||||||
// Draw second extrema
|
|
||||||
string secondExtremaName = extremaPrefix + "Second_" + TimeToString(secondExtremaTime);
|
|
||||||
DrawExtremaPoint(secondExtremaName, secondExtremaTime, priceSecondExtrema,
|
|
||||||
clrBlue, 233, "2nd Div");
|
|
||||||
|
|
||||||
Print("Second extrema detected - Divergence found",
|
|
||||||
", RSI: ", rsiSecondExtrema, ", Price: ", priceSecondExtrema);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Third extrema (must be between overbought/oversold levels)
|
|
||||||
else if(!hasThirdExtrema)
|
|
||||||
{
|
|
||||||
if(RSILastTwo > RSI_Oversold && RSILastTwo < RSI_Overbought)
|
|
||||||
{
|
|
||||||
hasThirdExtrema = true;
|
|
||||||
priceThirdExtrema = iClose(_Symbol, BarTimeFrame, 1);
|
|
||||||
rsiThirdExtrema = RSILastTwo;
|
|
||||||
thirdExtremaTime = iTime(_Symbol, BarTimeFrame, 1);
|
|
||||||
|
|
||||||
// Draw third extrema
|
|
||||||
string thirdExtremaName = extremaPrefix + "Third_" + TimeToString(thirdExtremaTime);
|
|
||||||
DrawExtremaPoint(thirdExtremaName, thirdExtremaTime, priceThirdExtrema,
|
|
||||||
clrMagenta, 232, "3rd Entry");
|
|
||||||
|
|
||||||
Print("Third extrema detected - Trade signal",
|
|
||||||
", RSI: ", rsiThirdExtrema, ", Price: ", priceThirdExtrema);
|
|
||||||
|
|
||||||
// Enter trade
|
|
||||||
if(isOverboughtExtrema)
|
|
||||||
{
|
|
||||||
if(!trade.Sell(BaseLotSize, _Symbol, 0, 0, 0, "RSI Divergence Sell"))
|
|
||||||
{
|
|
||||||
Print("Failed to execute sell order - resetting extrema");
|
|
||||||
ResetExtrema();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(!trade.Buy(BaseLotSize, _Symbol, 0, 0, 0, "RSI Divergence Buy"))
|
|
||||||
{
|
|
||||||
Print("Failed to execute buy order - resetting extrema");
|
|
||||||
ResetExtrema();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for exit conditions
|
|
||||||
if(PositionSelect(_Symbol))
|
|
||||||
{
|
|
||||||
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
|
||||||
if(posType == POSITION_TYPE_BUY && RSILast >= ExitBuyRSIThreshold)
|
|
||||||
{
|
|
||||||
trade.PositionClose(_Symbol);
|
|
||||||
ResetExtrema();
|
|
||||||
}
|
|
||||||
else if(posType == POSITION_TYPE_SELL && RSILast <= ExitSellRSIThreshold)
|
|
||||||
{
|
|
||||||
trade.PositionClose(_Symbol);
|
|
||||||
ResetExtrema();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Reset extrema flags and values |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void ResetExtrema()
|
|
||||||
{
|
|
||||||
// Clean up existing objects
|
|
||||||
CleanupExtremaObjects();
|
|
||||||
|
|
||||||
hasFirstExtrema = false;
|
|
||||||
hasSecondExtrema = false;
|
|
||||||
hasThirdExtrema = false;
|
|
||||||
isOverboughtExtrema = false;
|
|
||||||
priceFirstExtrema = 0;
|
|
||||||
rsiFirstExtrema = 0;
|
|
||||||
priceSecondExtrema = 0;
|
|
||||||
rsiSecondExtrema = 0;
|
|
||||||
priceThirdExtrema = 0;
|
|
||||||
rsiThirdExtrema = 0;
|
|
||||||
firstExtremaTime = 0;
|
|
||||||
secondExtremaTime = 0;
|
|
||||||
thirdExtremaTime = 0;
|
|
||||||
}
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
|
Before Width: | Height: | Size: 246 KiB |
@@ -1,655 +0,0 @@
|
|||||||
//+------------------------------------------------------------------+
|
|
||||||
//| RSIDivergenceRebound.mq5 |
|
|
||||||
//| Copyright 2024, MetaQuotes Ltd. |
|
|
||||||
//| https://www.mql5.com |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
#property copyright "Copyright 2024, MetaQuotes Ltd."
|
|
||||||
#property link "https://www.mql5.com"
|
|
||||||
#property version "1.00"
|
|
||||||
#property strict
|
|
||||||
|
|
||||||
#include <Trade\Trade.mqh> // Include CTrade class
|
|
||||||
|
|
||||||
// Input Parameters
|
|
||||||
input int RSI_Period = 14; // RSI Period
|
|
||||||
input int RSI_Overbought = 71; // RSI Overbought Level
|
|
||||||
input int RSI_Oversold = 33; // RSI Oversold Level
|
|
||||||
input double BaseLotSize = 0.01; // Base Lot Size
|
|
||||||
input ENUM_TIMEFRAMES BarTimeFrame = PERIOD_H6; // Timeframe for bar updates
|
|
||||||
input double ExitBuyRSIThreshold = 60; // RSI level to exit buy positions
|
|
||||||
input double ExitSellRSIThreshold = 40; // RSI level to exit sell positions
|
|
||||||
input int ExtremaExpiryBars = 45; // Number of bars before extrema expire
|
|
||||||
input int StuckTradeBars = 6; // Number of bars before considering trade stuck
|
|
||||||
input double HedgeLotMultiplier = 6.0; // Multiplier for hedge position lot size
|
|
||||||
|
|
||||||
// Global Variables
|
|
||||||
int rsiHandle; // RSI indicator handle
|
|
||||||
CTrade trade; // Trade object
|
|
||||||
datetime lastBarTime = 0; // Last bar time
|
|
||||||
double RSILastThree = 0; // Third last RSI value
|
|
||||||
double RSILastTwo = 0; // Second last RSI value
|
|
||||||
double RSILast = 0; // Last RSI value
|
|
||||||
bool hasFirstExtrema = false; // Flag for first extrema
|
|
||||||
bool hasSecondExtrema = false; // Flag for second extrema
|
|
||||||
bool hasThirdExtrema = false; // Flag for third extrema
|
|
||||||
bool isOverboughtExtrema = false; // Flag for extrema type
|
|
||||||
double priceFirstExtrema = 0; // Price at first extrema
|
|
||||||
double rsiFirstExtrema = 0; // RSI at first extrema
|
|
||||||
double priceSecondExtrema = 0; // Price at second extrema
|
|
||||||
double rsiSecondExtrema = 0; // RSI at second extrema
|
|
||||||
double priceThirdExtrema = 0; // Price at third extrema
|
|
||||||
double rsiThirdExtrema = 0; // RSI at third extrema
|
|
||||||
string extremaPrefix = "Ext_"; // Prefix for extrema objects
|
|
||||||
datetime firstExtremaTime = 0; // Time of first extrema
|
|
||||||
datetime secondExtremaTime = 0; // Time of second extrema
|
|
||||||
datetime thirdExtremaTime = 0; // Time of third extrema
|
|
||||||
datetime extremaStartTime = 0; // Time when first extrema was detected
|
|
||||||
datetime positionOpenTime = 0; // Time when position was opened
|
|
||||||
bool isHedged = false; // Flag for hedge position
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Draw extrema point |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void DrawExtremaPoint(string name, datetime time, double price, color clr, int shape, string label)
|
|
||||||
{
|
|
||||||
// Create the point
|
|
||||||
ObjectCreate(0, name, OBJ_ARROW, 0, time, price);
|
|
||||||
ObjectSetInteger(0, name, OBJPROP_ARROWCODE, shape);
|
|
||||||
ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
|
|
||||||
ObjectSetInteger(0, name, OBJPROP_WIDTH, 2);
|
|
||||||
ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
|
|
||||||
ObjectSetInteger(0, name, OBJPROP_HIDDEN, false);
|
|
||||||
ObjectSetInteger(0, name, OBJPROP_BACK, true);
|
|
||||||
|
|
||||||
// Add label
|
|
||||||
string labelName = name + "_Label";
|
|
||||||
ObjectCreate(0, labelName, OBJ_TEXT, 0, time, price);
|
|
||||||
ObjectSetString(0, labelName, OBJPROP_TEXT, label);
|
|
||||||
ObjectSetInteger(0, labelName, OBJPROP_COLOR, clr);
|
|
||||||
ObjectSetInteger(0, labelName, OBJPROP_FONTSIZE, 8);
|
|
||||||
ObjectSetInteger(0, labelName, OBJPROP_SELECTABLE, false);
|
|
||||||
ObjectSetInteger(0, labelName, OBJPROP_HIDDEN, false);
|
|
||||||
ObjectSetInteger(0, labelName, OBJPROP_BACK, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Clean up extrema objects |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void CleanupExtremaObjects()
|
|
||||||
{
|
|
||||||
for(int i = ObjectsTotal(0, 0, -1) - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
string name = ObjectName(0, i, 0, -1);
|
|
||||||
if(StringFind(name, extremaPrefix) == 0)
|
|
||||||
{
|
|
||||||
ObjectDelete(0, name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Check if trade is stuck |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
bool IsTradeStuck()
|
|
||||||
{
|
|
||||||
if(!PositionSelect(_Symbol))
|
|
||||||
{
|
|
||||||
Print("No position selected - cannot check if trade is stuck");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(positionOpenTime == 0)
|
|
||||||
{
|
|
||||||
Print("Position open time not set - cannot check if trade is stuck");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
datetime currentTime = iTime(_Symbol, BarTimeFrame, 0);
|
|
||||||
int barsPassed = (int)((currentTime - positionOpenTime) / PeriodSeconds(BarTimeFrame));
|
|
||||||
|
|
||||||
Print("Trade Stuck Check - Current Time: ", TimeToString(currentTime),
|
|
||||||
", Position Open Time: ", TimeToString(positionOpenTime),
|
|
||||||
", Bars Passed: ", barsPassed,
|
|
||||||
", Stuck Trade Bars: ", StuckTradeBars);
|
|
||||||
|
|
||||||
return barsPassed >= StuckTradeBars;
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Place hedge trade |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void PlaceHedgeTrade()
|
|
||||||
{
|
|
||||||
if(isHedged)
|
|
||||||
{
|
|
||||||
Print("Hedge position already exists - skipping");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!PositionSelect(_Symbol))
|
|
||||||
{
|
|
||||||
Print("No position selected - cannot place hedge");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
|
||||||
double currentLot = PositionGetDouble(POSITION_VOLUME);
|
|
||||||
double hedgeLot = currentLot * HedgeLotMultiplier;
|
|
||||||
|
|
||||||
Print("Placing hedge trade - Current Position: ", EnumToString(posType),
|
|
||||||
", Current Lot: ", currentLot,
|
|
||||||
", Hedge Lot: ", hedgeLot);
|
|
||||||
|
|
||||||
// Set different magic number for hedge positions
|
|
||||||
trade.SetExpertMagicNumber(654321);
|
|
||||||
|
|
||||||
if(posType == POSITION_TYPE_BUY)
|
|
||||||
{
|
|
||||||
if(trade.Sell(hedgeLot, _Symbol, 0, 0, 0, "RSI Hedge Sell"))
|
|
||||||
{
|
|
||||||
isHedged = true;
|
|
||||||
Print("Hedge sell position opened with lot size: ", hedgeLot);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Print("Failed to open hedge sell position");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(posType == POSITION_TYPE_SELL)
|
|
||||||
{
|
|
||||||
if(trade.Buy(hedgeLot, _Symbol, 0, 0, 0, "RSI Hedge Buy"))
|
|
||||||
{
|
|
||||||
isHedged = true;
|
|
||||||
Print("Hedge buy position opened with lot size: ", hedgeLot);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Print("Failed to open hedge buy position");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset magic number back to original
|
|
||||||
trade.SetExpertMagicNumber(123456);
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Close all positions |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void CloseAllPositions()
|
|
||||||
{
|
|
||||||
Print("Starting to close all positions");
|
|
||||||
|
|
||||||
// Close all positions for the symbol
|
|
||||||
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
ulong ticket = PositionGetTicket(i);
|
|
||||||
if(ticket == 0)
|
|
||||||
{
|
|
||||||
Print("Failed to get position ticket for index ", i);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!PositionSelectByTicket(ticket))
|
|
||||||
{
|
|
||||||
Print("Failed to select position with ticket ", ticket);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(PositionGetString(POSITION_SYMBOL) != _Symbol)
|
|
||||||
{
|
|
||||||
Print("Position ", ticket, " is not for symbol ", _Symbol);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Print("Closing position - Ticket: ", ticket,
|
|
||||||
", Magic: ", PositionGetInteger(POSITION_MAGIC),
|
|
||||||
", Type: ", EnumToString((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE)));
|
|
||||||
|
|
||||||
if(!trade.PositionClose(ticket))
|
|
||||||
{
|
|
||||||
Print("Failed to close position with ticket ", ticket);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Print("Successfully closed position with ticket ", ticket);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isHedged = false;
|
|
||||||
positionOpenTime = 0;
|
|
||||||
Print("All positions closed");
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Expert initialization function |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
int OnInit()
|
|
||||||
{
|
|
||||||
// Initialize RSI indicator
|
|
||||||
rsiHandle = iRSI(_Symbol, BarTimeFrame, RSI_Period, PRICE_CLOSE);
|
|
||||||
|
|
||||||
if(rsiHandle == INVALID_HANDLE)
|
|
||||||
{
|
|
||||||
Print("Error creating RSI indicator");
|
|
||||||
return(INIT_FAILED);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize trade object
|
|
||||||
trade.SetExpertMagicNumber(123457);
|
|
||||||
|
|
||||||
Print("RSI Divergence Rebound Strategy Initialized");
|
|
||||||
Print("RSI Period: ", RSI_Period);
|
|
||||||
Print("Overbought Level: ", RSI_Overbought);
|
|
||||||
Print("Oversold Level: ", RSI_Oversold);
|
|
||||||
|
|
||||||
// Clean up any existing extrema objects
|
|
||||||
CleanupExtremaObjects();
|
|
||||||
|
|
||||||
positionOpenTime = 0;
|
|
||||||
isHedged = false;
|
|
||||||
|
|
||||||
return(INIT_SUCCEEDED);
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Expert deinitialization function |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void OnDeinit(const int reason)
|
|
||||||
{
|
|
||||||
// Clean up extrema objects
|
|
||||||
CleanupExtremaObjects();
|
|
||||||
|
|
||||||
IndicatorRelease(rsiHandle);
|
|
||||||
|
|
||||||
CloseAllPositions();
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Check for local extrema in RSI |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
bool IsLocalExtrema(double rsi1, double rsi2, double rsi3, bool& isMaxima)
|
|
||||||
{
|
|
||||||
if(rsi2 > rsi1 && rsi2 > rsi3)
|
|
||||||
{
|
|
||||||
isMaxima = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if(rsi2 < rsi1 && rsi2 < rsi3)
|
|
||||||
{
|
|
||||||
isMaxima = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Check for divergence patterns |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
bool CheckDivergence(double price1, double rsi1, double price2, double rsi2, bool isOverbought)
|
|
||||||
{
|
|
||||||
if(isOverbought)
|
|
||||||
{
|
|
||||||
// Bearish divergence (price makes higher high, RSI makes lower high)
|
|
||||||
if(price2 > price1 && rsi2 < rsi1)
|
|
||||||
return true;
|
|
||||||
// Hidden bearish divergence (price makes lower high, RSI makes higher high)
|
|
||||||
if(price2 < price1 && rsi2 > rsi1)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Bullish divergence (price makes lower low, RSI makes higher low)
|
|
||||||
if(price2 < price1 && rsi2 > rsi1)
|
|
||||||
return true;
|
|
||||||
// Hidden bullish divergence (price makes higher low, RSI makes lower low)
|
|
||||||
if(price2 > price1 && rsi2 < rsi1)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Check if market is open |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
bool IsMarketOpen()
|
|
||||||
{
|
|
||||||
MqlDateTime dt;
|
|
||||||
TimeCurrent(dt);
|
|
||||||
|
|
||||||
// Check if it's a weekend
|
|
||||||
if(dt.day_of_week == 0 || dt.day_of_week == 6)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Check if it's within trading hours (assuming 24/5 market)
|
|
||||||
// You can modify these hours based on your broker's trading hours
|
|
||||||
int hour = dt.hour;
|
|
||||||
int minute = dt.min;
|
|
||||||
|
|
||||||
// Market is open 24/5 except weekends
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Check if extrema has expired |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
bool HasExtremaExpired()
|
|
||||||
{
|
|
||||||
if(extremaStartTime == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
datetime currentTime = iTime(_Symbol, BarTimeFrame, 0);
|
|
||||||
int barsPassed = (int)((currentTime - extremaStartTime) / PeriodSeconds(BarTimeFrame));
|
|
||||||
|
|
||||||
return barsPassed >= ExtremaExpiryBars;
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Check if loss is resolved after hedging |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
bool IsLossResolved()
|
|
||||||
{
|
|
||||||
if(!isHedged)
|
|
||||||
{
|
|
||||||
Print("Loss Resolution Check - No hedge position exists");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
double originalProfit = 0;
|
|
||||||
double hedgeProfit = 0;
|
|
||||||
bool foundOriginal = false;
|
|
||||||
bool foundHedge = false;
|
|
||||||
|
|
||||||
Print("Loss Resolution Check - Starting position scan");
|
|
||||||
|
|
||||||
// Calculate total profit from all positions
|
|
||||||
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
ulong ticket = PositionGetTicket(i);
|
|
||||||
if(ticket == 0)
|
|
||||||
{
|
|
||||||
Print("Loss Resolution Check - Failed to get position ticket for index ", i);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!PositionSelectByTicket(ticket))
|
|
||||||
{
|
|
||||||
Print("Loss Resolution Check - Failed to select position with ticket ", ticket);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(PositionGetString(POSITION_SYMBOL) != _Symbol)
|
|
||||||
{
|
|
||||||
Print("Loss Resolution Check - Position ", ticket, " is not for symbol ", _Symbol);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
double profit = PositionGetDouble(POSITION_PROFIT);
|
|
||||||
int magic = (int)PositionGetInteger(POSITION_MAGIC);
|
|
||||||
|
|
||||||
Print("Loss Resolution Check - Position ", ticket,
|
|
||||||
", Magic: ", magic,
|
|
||||||
", Profit: ", profit);
|
|
||||||
|
|
||||||
if(magic == 123456) // Original position
|
|
||||||
{
|
|
||||||
originalProfit = profit;
|
|
||||||
foundOriginal = true;
|
|
||||||
Print("Loss Resolution Check - Found original position with profit: ", profit);
|
|
||||||
}
|
|
||||||
else if(magic == 654321) // Hedge position
|
|
||||||
{
|
|
||||||
hedgeProfit = profit;
|
|
||||||
foundHedge = true;
|
|
||||||
Print("Loss Resolution Check - Found hedge position with profit: ", profit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!foundOriginal)
|
|
||||||
Print("Loss Resolution Check - Warning: Original position not found");
|
|
||||||
if(!foundHedge)
|
|
||||||
Print("Loss Resolution Check - Warning: Hedge position not found");
|
|
||||||
|
|
||||||
double totalProfit = originalProfit + hedgeProfit;
|
|
||||||
Print("Loss Resolution Check - Final Calculation -",
|
|
||||||
"\nOriginal Profit: ", originalProfit,
|
|
||||||
"\nHedge Profit: ", hedgeProfit,
|
|
||||||
"\nTotal Profit: ", totalProfit,
|
|
||||||
"\nIs Resolved: ", totalProfit >= 0);
|
|
||||||
|
|
||||||
return totalProfit >= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Check if main trade is in loss |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
bool IsMainTradeInLoss()
|
|
||||||
{
|
|
||||||
if(!PositionSelect(_Symbol))
|
|
||||||
{
|
|
||||||
Print("No position selected - cannot check for loss");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(PositionGetInteger(POSITION_MAGIC) != 123456)
|
|
||||||
{
|
|
||||||
Print("Not a main trade position - cannot check for loss");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
double profit = PositionGetDouble(POSITION_PROFIT);
|
|
||||||
Print("Main Trade Profit Check - Profit: ", profit);
|
|
||||||
|
|
||||||
return profit < 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Expert tick function |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void OnTick()
|
|
||||||
{
|
|
||||||
// Check if market is open
|
|
||||||
if(!IsMarketOpen())
|
|
||||||
{
|
|
||||||
Print("Market is closed - resetting extrema");
|
|
||||||
ResetExtrema();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for new bar
|
|
||||||
datetime currentBarTime = iTime(_Symbol, BarTimeFrame, 0);
|
|
||||||
if(currentBarTime == lastBarTime)
|
|
||||||
return;
|
|
||||||
lastBarTime = currentBarTime;
|
|
||||||
|
|
||||||
// Get current RSI value
|
|
||||||
double rsiBuffer[];
|
|
||||||
ArraySetAsSeries(rsiBuffer, true);
|
|
||||||
if(CopyBuffer(rsiHandle, 0, 0, 1, rsiBuffer) != 1)
|
|
||||||
{
|
|
||||||
Print("Error copying RSI buffer");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update RSI queue
|
|
||||||
RSILastThree = RSILastTwo;
|
|
||||||
RSILastTwo = RSILast;
|
|
||||||
RSILast = rsiBuffer[0];
|
|
||||||
|
|
||||||
// Check if we have enough RSI values
|
|
||||||
if(RSILastThree == 0 || RSILastTwo == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Check for local extrema
|
|
||||||
bool isMaxima;
|
|
||||||
if(IsLocalExtrema(RSILastThree, RSILastTwo, RSILast, isMaxima))
|
|
||||||
{
|
|
||||||
|
|
||||||
if(!hasFirstExtrema)
|
|
||||||
{
|
|
||||||
// For overbought condition, we need a maxima
|
|
||||||
if(isMaxima && RSILastTwo >= RSI_Overbought)
|
|
||||||
{
|
|
||||||
hasFirstExtrema = true;
|
|
||||||
isOverboughtExtrema = true;
|
|
||||||
priceFirstExtrema = iClose(_Symbol, BarTimeFrame, 1);
|
|
||||||
rsiFirstExtrema = RSILastTwo;
|
|
||||||
firstExtremaTime = iTime(_Symbol, BarTimeFrame, 1);
|
|
||||||
extremaStartTime = firstExtremaTime;
|
|
||||||
|
|
||||||
// Draw first extrema
|
|
||||||
string firstExtremaName = extremaPrefix + "First_" + TimeToString(firstExtremaTime);
|
|
||||||
DrawExtremaPoint(firstExtremaName, firstExtremaTime, priceFirstExtrema,
|
|
||||||
clrRed, 234, "1st OB");
|
|
||||||
|
|
||||||
Print("First extrema detected - Type: Overbought",
|
|
||||||
", RSI: ", rsiFirstExtrema, ", Price: ", priceFirstExtrema);
|
|
||||||
}
|
|
||||||
// For oversold condition, we need a minima
|
|
||||||
else if(!isMaxima && RSILastTwo <= RSI_Oversold)
|
|
||||||
{
|
|
||||||
hasFirstExtrema = true;
|
|
||||||
isOverboughtExtrema = false;
|
|
||||||
priceFirstExtrema = iClose(_Symbol, BarTimeFrame, 1);
|
|
||||||
rsiFirstExtrema = RSILastTwo;
|
|
||||||
firstExtremaTime = iTime(_Symbol, BarTimeFrame, 1);
|
|
||||||
extremaStartTime = firstExtremaTime;
|
|
||||||
|
|
||||||
// Draw first extrema
|
|
||||||
string firstExtremaName = extremaPrefix + "First_" + TimeToString(firstExtremaTime);
|
|
||||||
DrawExtremaPoint(firstExtremaName, firstExtremaTime, priceFirstExtrema,
|
|
||||||
clrGreen, 234, "1st OS");
|
|
||||||
|
|
||||||
Print("First extrema detected - Type: Oversold",
|
|
||||||
", RSI: ", rsiFirstExtrema, ", Price: ", priceFirstExtrema);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Second extrema (check for divergence)
|
|
||||||
else if(!hasSecondExtrema)
|
|
||||||
{
|
|
||||||
priceSecondExtrema = iClose(_Symbol, BarTimeFrame, 1);
|
|
||||||
rsiSecondExtrema = RSILastTwo;
|
|
||||||
secondExtremaTime = iTime(_Symbol, BarTimeFrame, 1);
|
|
||||||
|
|
||||||
if(CheckDivergence(priceFirstExtrema, rsiFirstExtrema, priceSecondExtrema, rsiSecondExtrema, isOverboughtExtrema))
|
|
||||||
{
|
|
||||||
hasSecondExtrema = true;
|
|
||||||
|
|
||||||
// Draw second extrema
|
|
||||||
string secondExtremaName = extremaPrefix + "Second_" + TimeToString(secondExtremaTime);
|
|
||||||
DrawExtremaPoint(secondExtremaName, secondExtremaTime, priceSecondExtrema,
|
|
||||||
clrBlue, 233, "2nd Div");
|
|
||||||
|
|
||||||
Print("Second extrema detected - Divergence found",
|
|
||||||
", RSI: ", rsiSecondExtrema, ", Price: ", priceSecondExtrema);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Third extrema (must be between overbought/oversold levels)
|
|
||||||
else if(!hasThirdExtrema)
|
|
||||||
{
|
|
||||||
if(RSILastTwo > RSI_Oversold && RSILastTwo < RSI_Overbought)
|
|
||||||
{
|
|
||||||
hasThirdExtrema = true;
|
|
||||||
priceThirdExtrema = iClose(_Symbol, BarTimeFrame, 1);
|
|
||||||
rsiThirdExtrema = RSILastTwo;
|
|
||||||
thirdExtremaTime = iTime(_Symbol, BarTimeFrame, 1);
|
|
||||||
|
|
||||||
// Draw third extrema
|
|
||||||
string thirdExtremaName = extremaPrefix + "Third_" + TimeToString(thirdExtremaTime);
|
|
||||||
DrawExtremaPoint(thirdExtremaName, thirdExtremaTime, priceThirdExtrema,
|
|
||||||
clrMagenta, 232, "3rd Entry");
|
|
||||||
|
|
||||||
Print("Third extrema detected - Trade signal",
|
|
||||||
", RSI: ", rsiThirdExtrema, ", Price: ", priceThirdExtrema);
|
|
||||||
|
|
||||||
// Enter trade
|
|
||||||
if(isOverboughtExtrema)
|
|
||||||
{
|
|
||||||
if(!trade.Sell(BaseLotSize, _Symbol, 0, 0, 0, "RSI Divergence Sell"))
|
|
||||||
{
|
|
||||||
Print("Failed to execute sell order - resetting extrema");
|
|
||||||
ResetExtrema();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
positionOpenTime = iTime(_Symbol, BarTimeFrame, 0);
|
|
||||||
Print("Sell position opened at: ", TimeToString(positionOpenTime));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(!trade.Buy(BaseLotSize, _Symbol, 0, 0, 0, "RSI Divergence Buy"))
|
|
||||||
{
|
|
||||||
Print("Failed to execute buy order - resetting extrema");
|
|
||||||
ResetExtrema();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
positionOpenTime = iTime(_Symbol, BarTimeFrame, 0);
|
|
||||||
Print("Buy position opened at: ", TimeToString(positionOpenTime));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for exit conditions and hedge
|
|
||||||
if(PositionSelect(_Symbol))
|
|
||||||
{
|
|
||||||
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
|
||||||
|
|
||||||
// Check if trade is stuck and in loss
|
|
||||||
if(IsTradeStuck() && IsMainTradeInLoss())
|
|
||||||
{
|
|
||||||
Print("Trade is stuck and in loss - placing hedge");
|
|
||||||
PlaceHedgeTrade();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if loss is resolved after hedging
|
|
||||||
if(isHedged && IsLossResolved())
|
|
||||||
{
|
|
||||||
Print("Loss resolved - closing all positions");
|
|
||||||
CloseAllPositions();
|
|
||||||
ResetExtrema();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check RSI exit conditions
|
|
||||||
if(posType == POSITION_TYPE_BUY && RSILast >= ExitBuyRSIThreshold)
|
|
||||||
{
|
|
||||||
CloseAllPositions();
|
|
||||||
ResetExtrema();
|
|
||||||
}
|
|
||||||
else if(posType == POSITION_TYPE_SELL && RSILast <= ExitSellRSIThreshold)
|
|
||||||
{
|
|
||||||
CloseAllPositions();
|
|
||||||
ResetExtrema();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Reset extrema flags and values |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void ResetExtrema()
|
|
||||||
{
|
|
||||||
// Clean up existing objects
|
|
||||||
CleanupExtremaObjects();
|
|
||||||
|
|
||||||
hasFirstExtrema = false;
|
|
||||||
hasSecondExtrema = false;
|
|
||||||
hasThirdExtrema = false;
|
|
||||||
isOverboughtExtrema = false;
|
|
||||||
priceFirstExtrema = 0;
|
|
||||||
rsiFirstExtrema = 0;
|
|
||||||
priceSecondExtrema = 0;
|
|
||||||
rsiSecondExtrema = 0;
|
|
||||||
priceThirdExtrema = 0;
|
|
||||||
rsiThirdExtrema = 0;
|
|
||||||
firstExtremaTime = 0;
|
|
||||||
secondExtremaTime = 0;
|
|
||||||
thirdExtremaTime = 0;
|
|
||||||
extremaStartTime = 0;
|
|
||||||
positionOpenTime = 0;
|
|
||||||
isHedged = false;
|
|
||||||
}
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
|
Before Width: | Height: | Size: 255 KiB |
|
Before Width: | Height: | Size: 273 KiB |
@@ -1,441 +0,0 @@
|
|||||||
//+------------------------------------------------------------------+
|
|
||||||
//| RSIDivergenceRebound.mq5 |
|
|
||||||
//| Copyright 2024, MetaQuotes Ltd. |
|
|
||||||
//| https://www.mql5.com |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
#property copyright "Copyright 2024, MetaQuotes Ltd."
|
|
||||||
#property link "https://www.mql5.com"
|
|
||||||
#property version "1.00"
|
|
||||||
#property strict
|
|
||||||
|
|
||||||
// Input Parameters
|
|
||||||
input int RSI_Period = 14; // RSI Period
|
|
||||||
input int RSI_Overbought = 70; // RSI Overbought Level
|
|
||||||
input int RSI_Oversold = 30; // RSI Oversold Level
|
|
||||||
input double BaseLotSize = 0.01; // Base Lot Size
|
|
||||||
input int ATR_Period = 14; // ATR Period
|
|
||||||
input double ATR_SL_Multiplier = 3.0; // ATR Stop Loss Multiplier
|
|
||||||
input double ATR_TP_Multiplier = 10.0; // ATR Take Profit Multiplier
|
|
||||||
input int MaxSpread = 50; // Maximum Spread in Points
|
|
||||||
input int DivergenceLookback = 9; // Number of bars to look back for divergence
|
|
||||||
input int MinTradeInterval = 30; // Minimum minutes between trades
|
|
||||||
input double MaxRiskPercent = 2.0; // Maximum risk per trade (% of balance)
|
|
||||||
input double MaxDrawdownPercent = 10.0; // Maximum drawdown before reset (% of balance)
|
|
||||||
input int MaxConsecutiveLosses = 3; // Maximum consecutive losses before reset
|
|
||||||
input double MaxLotSize = 0.1; // Maximum allowed lot size
|
|
||||||
input bool UseRegularDivergence = true; // Use regular divergence for reversals
|
|
||||||
input bool UseHiddenDivergence = true; // Use hidden divergence for continuations
|
|
||||||
input int RSI_ConfirmationBars = 19; // Number of bars to confirm RSI pattern
|
|
||||||
|
|
||||||
// Global Variables
|
|
||||||
int rsiHandle; // RSI indicator handle
|
|
||||||
int atrHandle; // ATR indicator handle
|
|
||||||
datetime lastTradeTime = 0; // Last trade time
|
|
||||||
datetime lastDebugTime = 0; // Last debug message time
|
|
||||||
double currentLotSize = 0; // Current lot size
|
|
||||||
bool lastTradeWasWin = false; // Flag for last trade result
|
|
||||||
int consecutiveLosses = 0; // Count of consecutive losses
|
|
||||||
double initialBalance = 0; // Initial account balance
|
|
||||||
double maxBalance = 0; // Maximum balance reached
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Expert initialization function |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
int OnInit()
|
|
||||||
{
|
|
||||||
// Initialize indicators
|
|
||||||
rsiHandle = iRSI(_Symbol, PERIOD_H1, RSI_Period, PRICE_CLOSE);
|
|
||||||
atrHandle = iATR(_Symbol, PERIOD_H1, ATR_Period);
|
|
||||||
|
|
||||||
if(rsiHandle == INVALID_HANDLE || atrHandle == INVALID_HANDLE)
|
|
||||||
{
|
|
||||||
Print("Error creating indicators");
|
|
||||||
return(INIT_FAILED);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize variables
|
|
||||||
currentLotSize = BaseLotSize;
|
|
||||||
lastTradeWasWin = false;
|
|
||||||
lastTradeTime = 0;
|
|
||||||
consecutiveLosses = 0;
|
|
||||||
initialBalance = AccountInfoDouble(ACCOUNT_BALANCE);
|
|
||||||
maxBalance = initialBalance;
|
|
||||||
|
|
||||||
Print("RSI Divergence Rebound Strategy Initialized");
|
|
||||||
Print("Base Lot Size: ", BaseLotSize);
|
|
||||||
Print("RSI Period: ", RSI_Period, ", ATR Period: ", ATR_Period);
|
|
||||||
Print("Max Risk per Trade: ", MaxRiskPercent, "%");
|
|
||||||
Print("Max Drawdown: ", MaxDrawdownPercent, "%");
|
|
||||||
|
|
||||||
return(INIT_SUCCEEDED);
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Expert deinitialization function |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void OnDeinit(const int reason)
|
|
||||||
{
|
|
||||||
// Release indicator handles
|
|
||||||
IndicatorRelease(rsiHandle);
|
|
||||||
IndicatorRelease(atrHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Get ATR value for stop loss and take profit calculations |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
double GetATRValue()
|
|
||||||
{
|
|
||||||
double atrBuffer[];
|
|
||||||
ArraySetAsSeries(atrBuffer, true);
|
|
||||||
|
|
||||||
if(CopyBuffer(atrHandle, 0, 0, 1, atrBuffer) != 1)
|
|
||||||
{
|
|
||||||
Print("Error copying ATR buffer");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return atrBuffer[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Check for RSI divergence patterns |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
int CheckRSIDivergence()
|
|
||||||
{
|
|
||||||
double rsiBuffer[];
|
|
||||||
double highBuffer[];
|
|
||||||
double lowBuffer[];
|
|
||||||
|
|
||||||
ArraySetAsSeries(rsiBuffer, true);
|
|
||||||
ArraySetAsSeries(highBuffer, true);
|
|
||||||
ArraySetAsSeries(lowBuffer, true);
|
|
||||||
|
|
||||||
if(CopyBuffer(rsiHandle, 0, 0, DivergenceLookback + 1, rsiBuffer) != DivergenceLookback + 1 ||
|
|
||||||
CopyHigh(_Symbol, PERIOD_H1, 0, DivergenceLookback + 1, highBuffer) != DivergenceLookback + 1 ||
|
|
||||||
CopyLow(_Symbol, PERIOD_H1, 0, DivergenceLookback + 1, lowBuffer) != DivergenceLookback + 1)
|
|
||||||
{
|
|
||||||
Print("Error copying data for divergence check");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for regular bullish divergence (price makes lower low, RSI makes higher low)
|
|
||||||
if(UseRegularDivergence)
|
|
||||||
{
|
|
||||||
for(int i = 1; i < DivergenceLookback; i++)
|
|
||||||
{
|
|
||||||
if(lowBuffer[i] < lowBuffer[i+1] && rsiBuffer[i] > rsiBuffer[i+1] &&
|
|
||||||
rsiBuffer[i] > RSI_Oversold && rsiBuffer[i] < RSI_Overbought)
|
|
||||||
{
|
|
||||||
// Confirm RSI is making higher lows
|
|
||||||
if(rsiBuffer[0] > rsiBuffer[1] && rsiBuffer[1] > rsiBuffer[2])
|
|
||||||
{
|
|
||||||
Print("Regular bullish divergence detected");
|
|
||||||
return 1; // Bullish signal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for regular bearish divergence (price makes higher high, RSI makes lower high)
|
|
||||||
for(int i = 1; i < DivergenceLookback; i++)
|
|
||||||
{
|
|
||||||
if(highBuffer[i] > highBuffer[i+1] && rsiBuffer[i] < rsiBuffer[i+1] &&
|
|
||||||
rsiBuffer[i] > RSI_Oversold && rsiBuffer[i] < RSI_Overbought)
|
|
||||||
{
|
|
||||||
// Confirm RSI is making lower highs
|
|
||||||
if(rsiBuffer[0] < rsiBuffer[1] && rsiBuffer[1] < rsiBuffer[2])
|
|
||||||
{
|
|
||||||
Print("Regular bearish divergence detected");
|
|
||||||
return -1; // Bearish signal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for hidden bullish divergence (price makes higher low, RSI makes lower low)
|
|
||||||
if(UseHiddenDivergence)
|
|
||||||
{
|
|
||||||
for(int i = 1; i < DivergenceLookback; i++)
|
|
||||||
{
|
|
||||||
if(lowBuffer[i] > lowBuffer[i+1] && rsiBuffer[i] < rsiBuffer[i+1] &&
|
|
||||||
rsiBuffer[i] > RSI_Oversold && rsiBuffer[i] < RSI_Overbought)
|
|
||||||
{
|
|
||||||
// Confirm RSI is making higher lows
|
|
||||||
if(rsiBuffer[0] > rsiBuffer[1] && rsiBuffer[1] > rsiBuffer[2])
|
|
||||||
{
|
|
||||||
Print("Hidden bullish divergence detected");
|
|
||||||
return 1; // Bullish signal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for hidden bearish divergence (price makes lower high, RSI makes higher high)
|
|
||||||
for(int i = 1; i < DivergenceLookback; i++)
|
|
||||||
{
|
|
||||||
if(highBuffer[i] < highBuffer[i+1] && rsiBuffer[i] > rsiBuffer[i+1] &&
|
|
||||||
rsiBuffer[i] > RSI_Oversold && rsiBuffer[i] < RSI_Overbought)
|
|
||||||
{
|
|
||||||
// Confirm RSI is making lower highs
|
|
||||||
if(rsiBuffer[0] < rsiBuffer[1] && rsiBuffer[1] < rsiBuffer[2])
|
|
||||||
{
|
|
||||||
Print("Hidden bearish divergence detected");
|
|
||||||
return -1; // Bearish signal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0; // No signal
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Check if we can open a new position |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
bool CanOpenPosition()
|
|
||||||
{
|
|
||||||
// Check spread
|
|
||||||
long currentSpread = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
|
|
||||||
if(currentSpread > MaxSpread)
|
|
||||||
{
|
|
||||||
Print("Spread too high: ", currentSpread);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check minimum time between trades
|
|
||||||
datetime currentTime = TimeCurrent();
|
|
||||||
if(currentTime - lastTradeTime < MinTradeInterval * 60)
|
|
||||||
{
|
|
||||||
Print("Minimum time between trades not reached - Time since last trade: ",
|
|
||||||
(currentTime - lastTradeTime) / 60, " minutes");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for existing positions
|
|
||||||
int total = PositionsTotal();
|
|
||||||
for(int i = 0; i < total; i++)
|
|
||||||
{
|
|
||||||
ulong ticket = PositionGetTicket(i);
|
|
||||||
if(PositionSelectByTicket(ticket))
|
|
||||||
{
|
|
||||||
if(PositionGetString(POSITION_SYMBOL) == _Symbol)
|
|
||||||
{
|
|
||||||
Print("Position already exists - Ticket: ", ticket);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Open new position |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
bool OpenPosition(ENUM_POSITION_TYPE posType)
|
|
||||||
{
|
|
||||||
// Validate lot size before attempting to open position
|
|
||||||
double maxLotSize = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
|
|
||||||
double minLotSize = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
|
|
||||||
|
|
||||||
if(currentLotSize > maxLotSize || currentLotSize < minLotSize)
|
|
||||||
{
|
|
||||||
currentLotSize = BaseLotSize;
|
|
||||||
Print("Lot size out of limits - Resetting to base: ", currentLotSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate required margin for the position
|
|
||||||
double marginRequired = SymbolInfoDouble(_Symbol, SYMBOL_MARGIN_INITIAL) * currentLotSize;
|
|
||||||
double freeMargin = AccountInfoDouble(ACCOUNT_MARGIN_FREE);
|
|
||||||
|
|
||||||
// If not enough margin, reduce lot size
|
|
||||||
while(marginRequired > freeMargin && currentLotSize > minLotSize)
|
|
||||||
{
|
|
||||||
currentLotSize = NormalizeDouble(currentLotSize * 0.5, 2);
|
|
||||||
marginRequired = SymbolInfoDouble(_Symbol, SYMBOL_MARGIN_INITIAL) * currentLotSize;
|
|
||||||
Print("Insufficient margin - Reducing lot size to: ", currentLotSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If still not enough margin, reset to base lot size
|
|
||||||
if(marginRequired > freeMargin)
|
|
||||||
{
|
|
||||||
currentLotSize = BaseLotSize;
|
|
||||||
marginRequired = SymbolInfoDouble(_Symbol, SYMBOL_MARGIN_INITIAL) * currentLotSize;
|
|
||||||
Print("Still insufficient margin - Resetting to base lot size: ", currentLotSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get current ATR value
|
|
||||||
double atrValue = GetATRValue();
|
|
||||||
if(atrValue == 0)
|
|
||||||
{
|
|
||||||
Print("Error getting ATR value");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
double price = (posType == POSITION_TYPE_BUY) ? SymbolInfoDouble(_Symbol, SYMBOL_ASK)
|
|
||||||
: SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
|
||||||
|
|
||||||
double sl = (posType == POSITION_TYPE_BUY)
|
|
||||||
? price - (atrValue * ATR_SL_Multiplier)
|
|
||||||
: price + (atrValue * ATR_SL_Multiplier);
|
|
||||||
|
|
||||||
double tp = (posType == POSITION_TYPE_BUY)
|
|
||||||
? price + (atrValue * ATR_TP_Multiplier)
|
|
||||||
: price - (atrValue * ATR_TP_Multiplier);
|
|
||||||
|
|
||||||
MqlTradeRequest request = {};
|
|
||||||
MqlTradeResult result = {};
|
|
||||||
|
|
||||||
request.action = TRADE_ACTION_DEAL;
|
|
||||||
request.symbol = _Symbol;
|
|
||||||
request.volume = currentLotSize;
|
|
||||||
request.type = (posType == POSITION_TYPE_BUY) ? ORDER_TYPE_BUY : ORDER_TYPE_SELL;
|
|
||||||
request.price = price;
|
|
||||||
request.sl = sl;
|
|
||||||
request.tp = tp;
|
|
||||||
request.deviation = 10;
|
|
||||||
request.magic = 123456;
|
|
||||||
|
|
||||||
// Set filling mode for XAUUSD
|
|
||||||
request.type_filling = ORDER_FILLING_FOK; // Fill or Kill
|
|
||||||
|
|
||||||
// If FOK fails, try IOC
|
|
||||||
if(!OrderSend(request, result))
|
|
||||||
{
|
|
||||||
request.type_filling = ORDER_FILLING_IOC; // Immediate or Cancel
|
|
||||||
if(!OrderSend(request, result))
|
|
||||||
{
|
|
||||||
Print("Failed to open position. Error: ", GetLastError());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(result.retcode != TRADE_RETCODE_DONE)
|
|
||||||
{
|
|
||||||
Print("Order failed. Return code: ", result.retcode);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
lastTradeTime = TimeCurrent();
|
|
||||||
Print("Position opened successfully - Lot size: ", currentLotSize,
|
|
||||||
", ATR: ", atrValue,
|
|
||||||
", SL: ", sl,
|
|
||||||
", TP: ", tp);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Check if we need to reset due to drawdown or consecutive losses |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
bool NeedToReset()
|
|
||||||
{
|
|
||||||
double currentBalance = AccountInfoDouble(ACCOUNT_BALANCE);
|
|
||||||
double currentEquity = AccountInfoDouble(ACCOUNT_EQUITY);
|
|
||||||
|
|
||||||
// Update maximum balance
|
|
||||||
if(currentBalance > maxBalance)
|
|
||||||
maxBalance = currentBalance;
|
|
||||||
|
|
||||||
// Calculate current drawdown
|
|
||||||
double drawdownPercent = ((maxBalance - currentEquity) / maxBalance) * 100.0;
|
|
||||||
|
|
||||||
// Check if we've hit maximum drawdown
|
|
||||||
if(drawdownPercent >= MaxDrawdownPercent)
|
|
||||||
{
|
|
||||||
Print("Maximum drawdown reached - Drawdown: ", drawdownPercent, "%");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if we've hit maximum consecutive losses
|
|
||||||
if(consecutiveLosses >= MaxConsecutiveLosses)
|
|
||||||
{
|
|
||||||
Print("Maximum consecutive losses reached - Losses: ", consecutiveLosses);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Check for closed positions and update lot size |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void CheckClosedPositions()
|
|
||||||
{
|
|
||||||
static int lastTotal = 0;
|
|
||||||
int currentTotal = PositionsTotal();
|
|
||||||
|
|
||||||
// If we have fewer positions than before, a position was closed
|
|
||||||
if(currentTotal < lastTotal)
|
|
||||||
{
|
|
||||||
// Check history for the last closed position
|
|
||||||
HistorySelect(TimeCurrent() - 3600, TimeCurrent());
|
|
||||||
int historyTotal = HistoryDealsTotal();
|
|
||||||
|
|
||||||
if(historyTotal > 0)
|
|
||||||
{
|
|
||||||
ulong dealTicket = HistoryDealGetTicket(historyTotal - 1);
|
|
||||||
if(dealTicket > 0)
|
|
||||||
{
|
|
||||||
double dealProfit = HistoryDealGetDouble(dealTicket, DEAL_PROFIT);
|
|
||||||
bool isWin = (dealProfit > 0);
|
|
||||||
|
|
||||||
Print("Position closed - Profit: ", dealProfit,
|
|
||||||
", Win: ", isWin ? "Yes" : "No");
|
|
||||||
|
|
||||||
if(isWin)
|
|
||||||
{
|
|
||||||
lastTradeWasWin = true;
|
|
||||||
consecutiveLosses = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
lastTradeWasWin = false;
|
|
||||||
consecutiveLosses++;
|
|
||||||
|
|
||||||
// Check if we need to reset due to drawdown or consecutive losses
|
|
||||||
if(NeedToReset())
|
|
||||||
{
|
|
||||||
consecutiveLosses = 0;
|
|
||||||
Print("Reset triggered");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lastTotal = currentTotal;
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Expert tick function |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void OnTick()
|
|
||||||
{
|
|
||||||
datetime currentTime = TimeCurrent();
|
|
||||||
|
|
||||||
// Print debug info every minute
|
|
||||||
if(currentTime - lastDebugTime >= 60)
|
|
||||||
{
|
|
||||||
lastDebugTime = currentTime;
|
|
||||||
Print("Current lot size: ", currentLotSize,
|
|
||||||
", Last trade was win: ", lastTradeWasWin ? "Yes" : "No");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for closed positions and update lot size
|
|
||||||
CheckClosedPositions();
|
|
||||||
|
|
||||||
// Check for entry signals
|
|
||||||
if(CanOpenPosition())
|
|
||||||
{
|
|
||||||
int signal = CheckRSIDivergence();
|
|
||||||
|
|
||||||
if(signal == 1) // Bullish signal
|
|
||||||
{
|
|
||||||
Print("Opening buy position with lot size: ", currentLotSize);
|
|
||||||
OpenPosition(POSITION_TYPE_BUY);
|
|
||||||
}
|
|
||||||
else if(signal == -1) // Bearish signal
|
|
||||||
{
|
|
||||||
Print("Opening sell position with lot size: ", currentLotSize);
|
|
||||||
OpenPosition(POSITION_TYPE_SELL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 284 KiB |
|
Before Width: | Height: | Size: 257 KiB |
@@ -12,27 +12,27 @@
|
|||||||
|
|
||||||
// Input Parameters
|
// Input Parameters
|
||||||
input group "General Settings"
|
input group "General Settings"
|
||||||
input ENUM_TIMEFRAMES InpTimeframe = PERIOD_CURRENT; // Trading Timeframe
|
input ENUM_TIMEFRAMES InpTimeframe = PERIOD_H1; // Trading Timeframe
|
||||||
input double InpLotSize = 0.01; // Lot Size
|
input double InpLotSize = 0.01; // Lot Size
|
||||||
input int InpMagicNumberRSIFollow = 1001; // Magic Number RSI Follow
|
input int InpMagicNumberRSIFollow = 1001; // Magic Number RSI Follow
|
||||||
input int InpMagicNumberRSIReverse = 1002;// Magic Number RSI Reverse
|
input int InpMagicNumberRSIReverse = 1002;// Magic Number RSI Reverse
|
||||||
input int InpMagicNumberEMACross = 1003; // Magic Number EMA Cross
|
input int InpMagicNumberEMACross = 1003; // Magic Number EMA Cross
|
||||||
|
|
||||||
input group "Strategy Switches"
|
input group "Strategy Switches"
|
||||||
input bool InpEnableRSIFollow = false; // Enable RSI Follow Strategy
|
input bool InpEnableRSIFollow = true; // Enable RSI Follow Strategy
|
||||||
input bool InpEnableRSIReverse = true; // Enable RSI Reverse Strategy
|
input bool InpEnableRSIReverse = true; // Enable RSI Reverse Strategy
|
||||||
input bool InpEnableEMACross = false; // Enable EMA Cross Strategy
|
input bool InpEnableEMACross = true; // Enable EMA Cross Strategy
|
||||||
input bool InpEnableStrategyLock = false; // Enable Strategy Lock
|
input bool InpEnableStrategyLock = false; // Enable Strategy Lock
|
||||||
input double InpLockProfitThreshold = 0.0; // Lock Profit Threshold (pips)
|
input double InpLockProfitThreshold = 0.0; // Lock Profit Threshold (pips)
|
||||||
input bool InpCloseOppositeTrades = false; // Close Opposite Trades When Profiting
|
input bool InpCloseOppositeTrades = false; // Close Opposite Trades When Profiting
|
||||||
|
|
||||||
input group "RSI Follow Strategy"
|
input group "RSI Follow Strategy"
|
||||||
input int InpRSIPeriod = 14; // RSI Period
|
input int InpRSIPeriod = 87; // RSI Period
|
||||||
input int InpRSIOverbought = 70; // RSI Overbought Level
|
input int InpRSIOverbought = 72; // RSI Overbought Level
|
||||||
input int InpRSIOversold = 30; // RSI Oversold Level
|
input int InpRSIOversold = 50; // RSI Oversold Level
|
||||||
input int InpRSIExitLevel = 50; // RSI Exit Level
|
input int InpRSIExitLevel = 40; // RSI Exit Level
|
||||||
input int InpRSIFollowStartHour = 0; // RSI Follow Start Hour (0-23)
|
input int InpRSIFollowStartHour = 0; // RSI Follow Start Hour (0-23)
|
||||||
input int InpRSIFollowEndHour = 23; // RSI Follow End Hour (0-23)
|
input int InpRSIFollowEndHour = 7; // RSI Follow End Hour (0-23)
|
||||||
input bool InpRSIFollowCloseOutsideHours = true; // Close trades outside trading hours
|
input bool InpRSIFollowCloseOutsideHours = true; // Close trades outside trading hours
|
||||||
|
|
||||||
input group "RSI Reverse Strategy"
|
input group "RSI Reverse Strategy"
|
||||||
@@ -48,13 +48,13 @@ input int InpRSIReverseCooldownBars = 15; // RSI Reverse Cooldown (bars)
|
|||||||
input bool InpRSIReverseCooldownOnLoss = true; // Apply cooldown only on loss
|
input bool InpRSIReverseCooldownOnLoss = true; // Apply cooldown only on loss
|
||||||
|
|
||||||
input group "EMA Cross Strategy"
|
input group "EMA Cross Strategy"
|
||||||
input int InpEMAPeriod = 20; // EMA Period
|
input int InpEMAPeriod = 120; // EMA Period
|
||||||
input int InpEMACrossStartHour = 0; // EMA Cross Start Hour (0-23)
|
input int InpEMACrossStartHour = 8; // EMA Cross Start Hour (0-23)
|
||||||
input int InpEMACrossEndHour = 23; // EMA Cross End Hour (0-23)
|
input int InpEMACrossEndHour = 14; // EMA Cross End Hour (0-23)
|
||||||
input bool InpEMACrossCloseOutsideHours = true; // Close trades outside trading hours
|
input bool InpEMACrossCloseOutsideHours = true; // Close trades outside trading hours
|
||||||
input bool InpUseEMADistanceEntry = false; // Use EMA Distance Entry
|
input bool InpUseEMADistanceEntry = true; // Use EMA Distance Entry
|
||||||
input double InpEMADistancePips = 10.0; // EMA Distance Threshold (pips)
|
input double InpEMADistancePips = 160.0; // EMA Distance Threshold (pips)
|
||||||
input int InpEMADistancePeriod = 3; // EMA Distance Period (bars)
|
input int InpEMADistancePeriod = 26; // EMA Distance Period (bars)
|
||||||
|
|
||||||
// Global Variables
|
// Global Variables
|
||||||
int rsiHandle;
|
int rsiHandle;
|
||||||
|
After Width: | Height: | Size: 280 KiB |
@@ -12,16 +12,16 @@
|
|||||||
#include <Trade\Trade.mqh>
|
#include <Trade\Trade.mqh>
|
||||||
|
|
||||||
// Input parameters
|
// Input parameters
|
||||||
input int RSIPeriod = 14; // RSI period
|
input int RSIPeriod = 28; // RSI period
|
||||||
input double OverboughtLevel = 67; // Overbought level
|
input double OverboughtLevel = 64; // Overbought level
|
||||||
input double OversoldLevel = 17; // Oversold level
|
input double OversoldLevel = 13; // Oversold level
|
||||||
input int TakeProfitPips = 253; // Take profit in pips
|
input int TakeProfitPips = 175; // Take profit in pips
|
||||||
input int StopLossPips = 429; // Stop loss in pips
|
input int StopLossPips = 5; // Stop loss in pips
|
||||||
input double MaxLotSize = 0.1; // Maximum lot size
|
input double MaxLotSize = 0.1; // Maximum lot size
|
||||||
input int MaxSpread = 1000; // Maximum allowed spread in pips
|
input int MaxSpread = 1000; // Maximum allowed spread in pips
|
||||||
input int MaxDuration = 81; // Maximum trade duration in hours
|
input int MaxDuration = 140; // Maximum trade duration in hours
|
||||||
input bool UseStopLoss = false; // Use stop loss
|
input bool UseStopLoss = false; // Use stop loss
|
||||||
input bool UseTakeProfit = true; // Use take profit
|
input bool UseTakeProfit = false; // Use take profit
|
||||||
input bool UseRSIExit = true; // Use RSI for exit
|
input bool UseRSIExit = true; // Use RSI for exit
|
||||||
input double RSIExitLevel = 49; // RSI level to exit (50 = neutral)
|
input double RSIExitLevel = 49; // RSI level to exit (50 = neutral)
|
||||||
input bool CloseOutsideSession = false; // Close trades outside Asian session
|
input bool CloseOutsideSession = false; // Close trades outside Asian session
|
||||||
@@ -221,6 +221,17 @@ bool CloseAllTrades(string reason = "")
|
|||||||
|
|
||||||
Print("Attempting to close all positions", (reason != "" ? " - " + reason : ""));
|
Print("Attempting to close all positions", (reason != "" ? " - " + reason : ""));
|
||||||
|
|
||||||
|
// Check if there are any positions with our magic number
|
||||||
|
bool hasOurPositions = false;
|
||||||
|
for(int i = 0; i < totalPositions; i++)
|
||||||
|
{
|
||||||
|
if(PositionGetSymbol(i) == _Symbol && PositionGetInteger(POSITION_MAGIC) == 123456)
|
||||||
|
{
|
||||||
|
hasOurPositions = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for(int i = totalPositions - 1; i >= 0; i--)
|
for(int i = totalPositions - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
if(PositionGetSymbol(i) == _Symbol)
|
if(PositionGetSymbol(i) == _Symbol)
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 305 KiB After Width: | Height: | Size: 268 KiB |
@@ -13,17 +13,17 @@
|
|||||||
|
|
||||||
// Input parameters
|
// Input parameters
|
||||||
input int RSIPeriod = 14; // RSI period
|
input int RSIPeriod = 14; // RSI period
|
||||||
input double OverboughtLevel = 77; // Overbought level
|
input double OverboughtLevel = 78; // Overbought level
|
||||||
input double OversoldLevel = 10; // Oversold level
|
input double OversoldLevel = 20; // Oversold level
|
||||||
input int TakeProfitPips = 116; // Take profit in pips
|
input int TakeProfitPips = 635; // Take profit in pips
|
||||||
input int StopLossPips = 247; // Stop loss in pips
|
input int StopLossPips = 290; // Stop loss in pips
|
||||||
input double MaxLotSize = 0.05; // Maximum lot size
|
input double MaxLotSize = 0.1; // Maximum lot size
|
||||||
input int MaxSpread = 1000; // Maximum allowed spread in pips
|
input int MaxSpread = 1000; // Maximum allowed spread in pips
|
||||||
input int MaxDuration = 67; // Maximum trade duration in hours
|
input int MaxDuration = 22; // Maximum trade duration in hours
|
||||||
input bool UseStopLoss = true; // Use stop loss
|
input bool UseStopLoss = true; // Use stop loss
|
||||||
input bool UseTakeProfit = false; // Use take profit
|
input bool UseTakeProfit = false; // Use take profit
|
||||||
input bool UseRSIExit = true; // Use RSI for exit
|
input bool UseRSIExit = true; // Use RSI for exit
|
||||||
input double RSIExitLevel = 40; // RSI level to exit (50 = neutral)
|
input double RSIExitLevel = 57; // RSI level to exit (50 = neutral)
|
||||||
input bool CloseOutsideSession = false; // Close trades outside Asian session
|
input bool CloseOutsideSession = false; // Close trades outside Asian session
|
||||||
input color PanelBackground = clrBlack; // Panel background color
|
input color PanelBackground = clrBlack; // Panel background color
|
||||||
input color PanelText = clrWhite; // Panel text color
|
input color PanelText = clrWhite; // Panel text color
|
||||||
@@ -219,6 +219,21 @@ bool CloseAllTrades(string reason = "")
|
|||||||
if(totalPositions == 0)
|
if(totalPositions == 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
// Check if there are any positions with our magic number
|
||||||
|
bool hasOurPositions = false;
|
||||||
|
for(int i = 0; i < totalPositions; i++)
|
||||||
|
{
|
||||||
|
if(PositionGetSymbol(i) == _Symbol && PositionGetInteger(POSITION_MAGIC) == 123457)
|
||||||
|
{
|
||||||
|
hasOurPositions = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return if no positions with our magic number
|
||||||
|
if(!hasOurPositions)
|
||||||
|
return true;
|
||||||
|
|
||||||
Print("Attempting to close all positions", (reason != "" ? " - " + reason : ""));
|
Print("Attempting to close all positions", (reason != "" ? " - " + reason : ""));
|
||||||
|
|
||||||
for(int i = totalPositions - 1; i >= 0; i--)
|
for(int i = totalPositions - 1; i >= 0; i--)
|
||||||
@@ -407,7 +422,7 @@ void OnTick()
|
|||||||
// Set trade parameters
|
// Set trade parameters
|
||||||
trade.SetDeviationInPoints(3);
|
trade.SetDeviationInPoints(3);
|
||||||
trade.SetTypeFilling(ORDER_FILLING_IOC);
|
trade.SetTypeFilling(ORDER_FILLING_IOC);
|
||||||
trade.SetExpertMagicNumber(123456);
|
trade.SetExpertMagicNumber(123457);
|
||||||
|
|
||||||
// Place buy order using CTrade
|
// Place buy order using CTrade
|
||||||
if(!trade.Buy(MaxLotSize, _Symbol, currentAsk, sl, tp, "RSI Buy"))
|
if(!trade.Buy(MaxLotSize, _Symbol, currentAsk, sl, tp, "RSI Buy"))
|
||||||
@@ -437,7 +452,7 @@ void OnTick()
|
|||||||
// Set trade parameters
|
// Set trade parameters
|
||||||
trade.SetDeviationInPoints(3);
|
trade.SetDeviationInPoints(3);
|
||||||
trade.SetTypeFilling(ORDER_FILLING_IOC);
|
trade.SetTypeFilling(ORDER_FILLING_IOC);
|
||||||
trade.SetExpertMagicNumber(123456);
|
trade.SetExpertMagicNumber(123457);
|
||||||
|
|
||||||
// Place sell order using CTrade
|
// Place sell order using CTrade
|
||||||
if(!trade.Sell(MaxLotSize, _Symbol, currentBid, sl, tp, "RSI Sell"))
|
if(!trade.Sell(MaxLotSize, _Symbol, currentBid, sl, tp, "RSI Sell"))
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 292 KiB |
|
Before Width: | Height: | Size: 295 KiB After Width: | Height: | Size: 235 KiB |
@@ -1,477 +0,0 @@
|
|||||||
//+------------------------------------------------------------------+
|
|
||||||
//| RSIReverseFollow.mq5 |
|
|
||||||
//| Copyright 2024, MetaQuotes Ltd. |
|
|
||||||
//| https://www.mql5.com |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
#property copyright "Copyright 2024, MetaQuotes Ltd."
|
|
||||||
#property link "https://www.mql5.com"
|
|
||||||
#property version "1.00"
|
|
||||||
|
|
||||||
#include <Trade\Trade.mqh>
|
|
||||||
|
|
||||||
// Input parameters
|
|
||||||
input group "Timeframe Settings"
|
|
||||||
input ENUM_TIMEFRAMES InpTimeframe = PERIOD_M3; // Trading Timeframe
|
|
||||||
|
|
||||||
input group "RSI Settings"
|
|
||||||
input int InpRSIPeriod = 48; // RSI Period
|
|
||||||
input double InpRSIOverbought = 68; // RSI Overbought Level
|
|
||||||
input double InpRSIOversold = 12; // RSI Oversold Level
|
|
||||||
input double InpRSI50Distance = 4.0; // Distance from 50 to consider as near
|
|
||||||
|
|
||||||
input group "Strategy 1 - RSI 50 Touch"
|
|
||||||
input bool InpEnableStrategy1 = true; // Enable Strategy 1
|
|
||||||
input int InpMagicNumber1 = 123456; // Magic Number for Strategy 1
|
|
||||||
input double InpLotSize1 = 0.01; // Lot Size for Strategy 1
|
|
||||||
input bool InpEnableRSIExit1 = true; // Enable RSI-based exit for Strategy 1
|
|
||||||
input bool InpUseSLTPWithRSI1 = false; // Use SL/TP alongside RSI exits
|
|
||||||
input int InpStopLoss1 = 188; // Stop Loss in pips
|
|
||||||
input int InpTakeProfit1 = 547; // Take Profit in pips
|
|
||||||
input double InpRSIExitBuy1 = 97.0; // RSI level to exit buy trades
|
|
||||||
input double InpRSIExitSell1 = 20.0; // RSI level to exit sell trades
|
|
||||||
input int InpTrailingStop1 = 125; // Trailing Stop in pips
|
|
||||||
input int InpTrailingStep1 = 400; // Trailing Step in pips
|
|
||||||
input int InpMaxTradeDuration1 = 22; // Maximum trade duration (hours)
|
|
||||||
input double InpLossThreshold1 = 7.1; // Minimum loss threshold to close trade
|
|
||||||
|
|
||||||
input group "Strategy 2 - RSI Reversal"
|
|
||||||
input bool InpEnableStrategy2 = true; // Enable Strategy 2
|
|
||||||
input int InpMagicNumber2 = 123457; // Magic Number for Strategy 2
|
|
||||||
input double InpLotSize2 = 0.01; // Lot Size for Strategy 2
|
|
||||||
input bool InpEnableRSIExit2 = false; // Enable RSI-based exit for Strategy 2
|
|
||||||
input bool InpUseSLTPWithRSI2 = true; // Use SL/TP alongside RSI exits
|
|
||||||
input int InpStopLoss2 = 245; // Stop Loss in pips
|
|
||||||
input int InpTakeProfit2 = 410; // Take Profit in pips
|
|
||||||
input double InpRSIExitBuy2 = 70.0; // RSI level to exit buy trades
|
|
||||||
input double InpRSIExitSell2 = 5.0; // RSI level to exit sell trades
|
|
||||||
input int InpTrailingStop2 = 185; // Trailing Stop in pips
|
|
||||||
input int InpTrailingStep2 = 30; // Trailing Step in pips
|
|
||||||
input int InpMaxTradeDuration2 = 6; // Maximum trade duration (hours)
|
|
||||||
input double InpLossThreshold2 = 9.3; // Minimum loss threshold to close trade
|
|
||||||
|
|
||||||
input group "Trading Hours"
|
|
||||||
input int InpStartHour = 16; // Trading Session Start Hour
|
|
||||||
input int InpEndHour = 19; // Trading Session End Hour
|
|
||||||
input bool InpCloseOutsideHours = true;// Close trades outside trading hours
|
|
||||||
|
|
||||||
// Global variables
|
|
||||||
CTrade trade;
|
|
||||||
int rsiHandle;
|
|
||||||
double lastRSI[];
|
|
||||||
bool wasOverbought = false;
|
|
||||||
bool wasOversold = false;
|
|
||||||
datetime lastBarTime = 0;
|
|
||||||
bool debugMode = true; // Enable detailed logging
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Expert initialization function |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
int OnInit()
|
|
||||||
{
|
|
||||||
// Initialize RSI indicator
|
|
||||||
rsiHandle = iRSI(_Symbol, InpTimeframe, InpRSIPeriod, PRICE_CLOSE);
|
|
||||||
if(rsiHandle == INVALID_HANDLE)
|
|
||||||
{
|
|
||||||
Print("Error creating RSI indicator");
|
|
||||||
return INIT_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize trade settings
|
|
||||||
trade.SetExpertMagicNumber(InpMagicNumber1);
|
|
||||||
trade.SetMarginMode();
|
|
||||||
trade.SetTypeFillingBySymbol(_Symbol);
|
|
||||||
trade.SetDeviationInPoints(10);
|
|
||||||
|
|
||||||
// Initialize RSI array
|
|
||||||
ArraySetAsSeries(lastRSI, true);
|
|
||||||
ArrayResize(lastRSI, 3);
|
|
||||||
|
|
||||||
return(INIT_SUCCEEDED);
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Expert deinitialization function |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void OnDeinit(const int reason)
|
|
||||||
{
|
|
||||||
IndicatorRelease(rsiHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Check if new bar has formed |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
bool IsNewBar()
|
|
||||||
{
|
|
||||||
datetime time[];
|
|
||||||
if(CopyTime(_Symbol, InpTimeframe, 0, 1, time) > 0)
|
|
||||||
{
|
|
||||||
if(time[0] != lastBarTime)
|
|
||||||
{
|
|
||||||
lastBarTime = time[0];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Check if within trading hours |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
bool IsWithinTradingHours()
|
|
||||||
{
|
|
||||||
datetime currentTime = TimeCurrent();
|
|
||||||
MqlDateTime timeStruct;
|
|
||||||
TimeToStruct(currentTime, timeStruct);
|
|
||||||
|
|
||||||
return (timeStruct.hour >= InpStartHour && timeStruct.hour < InpEndHour);
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Check for RSI signals |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void CheckRSISignals()
|
|
||||||
{
|
|
||||||
// Get RSI values for current and previous bars
|
|
||||||
if(CopyBuffer(rsiHandle, 0, 0, 3, lastRSI) <= 0)
|
|
||||||
{
|
|
||||||
Print("Error getting RSI values");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for RSI extremes
|
|
||||||
if(lastRSI[0] >= InpRSIOverbought)
|
|
||||||
{
|
|
||||||
wasOverbought = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(lastRSI[0] <= InpRSIOversold)
|
|
||||||
{
|
|
||||||
wasOversold = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Check for trailing stop |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void CheckTrailingStop(int magic, int trailingStop, int trailingStep)
|
|
||||||
{
|
|
||||||
if(!PositionSelectByTicket(magic))
|
|
||||||
return;
|
|
||||||
|
|
||||||
double currentPrice = PositionGetDouble(POSITION_PRICE_CURRENT);
|
|
||||||
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
|
|
||||||
double stopLoss = PositionGetDouble(POSITION_SL);
|
|
||||||
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
|
||||||
|
|
||||||
double newStopLoss = 0;
|
|
||||||
double trailingStopPoints = trailingStop * _Point;
|
|
||||||
double trailingStepPoints = trailingStep * _Point;
|
|
||||||
|
|
||||||
if(posType == POSITION_TYPE_BUY)
|
|
||||||
{
|
|
||||||
if(currentPrice - openPrice > trailingStopPoints)
|
|
||||||
{
|
|
||||||
newStopLoss = currentPrice - trailingStopPoints;
|
|
||||||
if(newStopLoss > stopLoss + trailingStepPoints)
|
|
||||||
{
|
|
||||||
trade.PositionModify(magic, newStopLoss, PositionGetDouble(POSITION_TP));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(posType == POSITION_TYPE_SELL)
|
|
||||||
{
|
|
||||||
if(openPrice - currentPrice > trailingStopPoints)
|
|
||||||
{
|
|
||||||
newStopLoss = currentPrice + trailingStopPoints;
|
|
||||||
if(newStopLoss < stopLoss - trailingStepPoints || stopLoss == 0)
|
|
||||||
{
|
|
||||||
trade.PositionModify(magic, newStopLoss, PositionGetDouble(POSITION_TP));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Check for time-based exits |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void CheckTimeBasedExits(int magic, int maxDuration, double lossThreshold)
|
|
||||||
{
|
|
||||||
datetime currentTime = TimeCurrent();
|
|
||||||
|
|
||||||
if(PositionSelectByTicket(magic))
|
|
||||||
{
|
|
||||||
datetime openTime = (datetime)PositionGetInteger(POSITION_TIME);
|
|
||||||
double profit = PositionGetDouble(POSITION_PROFIT);
|
|
||||||
double swap = PositionGetDouble(POSITION_SWAP);
|
|
||||||
double totalLoss = profit + swap;
|
|
||||||
|
|
||||||
if(currentTime - openTime >= maxDuration * 3600)
|
|
||||||
{
|
|
||||||
if(totalLoss < -lossThreshold)
|
|
||||||
{
|
|
||||||
trade.PositionClose(magic);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Check for trading hours exits |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void CheckTradingHoursExits()
|
|
||||||
{
|
|
||||||
if(!InpCloseOutsideHours)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if(!IsWithinTradingHours())
|
|
||||||
{
|
|
||||||
// Close Strategy 1 positions
|
|
||||||
if(PositionSelectByTicket(InpMagicNumber1))
|
|
||||||
{
|
|
||||||
trade.PositionClose(InpMagicNumber1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close Strategy 2 positions
|
|
||||||
if(PositionSelectByTicket(InpMagicNumber2))
|
|
||||||
{
|
|
||||||
trade.PositionClose(InpMagicNumber2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Check for RSI-based exits |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void CheckRSIExits(int magic, bool enableRSIExit, double exitBuyLevel, double exitSellLevel)
|
|
||||||
{
|
|
||||||
if(!enableRSIExit)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Try to find position by magic number
|
|
||||||
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
if(PositionSelectByTicket(PositionGetTicket(i)))
|
|
||||||
{
|
|
||||||
if(PositionGetInteger(POSITION_MAGIC) == magic)
|
|
||||||
{
|
|
||||||
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
|
||||||
double currentRSI = lastRSI[0];
|
|
||||||
|
|
||||||
if(posType == POSITION_TYPE_BUY && currentRSI <= exitBuyLevel)
|
|
||||||
{
|
|
||||||
ulong ticket = PositionGetTicket(i);
|
|
||||||
if(trade.PositionClose(ticket))
|
|
||||||
{
|
|
||||||
Print("Strategy ", magic == InpMagicNumber1 ? "1" : "2", " Buy position closed due to RSI exit level",
|
|
||||||
"\nTicket: ", ticket,
|
|
||||||
"\nRSI: ", DoubleToString(currentRSI, 2),
|
|
||||||
"\nExit Level: ", DoubleToString(exitBuyLevel, 2));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Print("Failed to close Strategy ", magic == InpMagicNumber1 ? "1" : "2", " Buy position",
|
|
||||||
"\nTicket: ", ticket,
|
|
||||||
"\nRSI: ", DoubleToString(currentRSI, 2),
|
|
||||||
"\nExit Level: ", DoubleToString(exitBuyLevel, 2),
|
|
||||||
"\nError: ", GetLastError());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(posType == POSITION_TYPE_SELL && currentRSI >= exitSellLevel)
|
|
||||||
{
|
|
||||||
ulong ticket = PositionGetTicket(i);
|
|
||||||
if(trade.PositionClose(ticket))
|
|
||||||
{
|
|
||||||
Print("Strategy ", magic == InpMagicNumber1 ? "1" : "2", " Sell position closed due to RSI exit level",
|
|
||||||
"\nTicket: ", ticket,
|
|
||||||
"\nRSI: ", DoubleToString(currentRSI, 2),
|
|
||||||
"\nExit Level: ", DoubleToString(exitSellLevel, 2));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Print("Failed to close Strategy ", magic == InpMagicNumber1 ? "1" : "2", " Sell position",
|
|
||||||
"\nTicket: ", ticket,
|
|
||||||
"\nRSI: ", DoubleToString(currentRSI, 2),
|
|
||||||
"\nExit Level: ", DoubleToString(exitSellLevel, 2),
|
|
||||||
"\nError: ", GetLastError());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Expert tick function |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void OnTick()
|
|
||||||
{
|
|
||||||
// Check trading hours exits
|
|
||||||
CheckTradingHoursExits();
|
|
||||||
|
|
||||||
// Only process on new bar
|
|
||||||
if(!IsNewBar())
|
|
||||||
{
|
|
||||||
// Check trailing stops and time-based exits every tick
|
|
||||||
if(InpEnableStrategy1)
|
|
||||||
{
|
|
||||||
CheckTrailingStop(InpMagicNumber1, InpTrailingStop1, InpTrailingStep1);
|
|
||||||
CheckTimeBasedExits(InpMagicNumber1, InpMaxTradeDuration1, InpLossThreshold1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(InpEnableStrategy2)
|
|
||||||
{
|
|
||||||
CheckTrailingStop(InpMagicNumber2, InpTrailingStop2, InpTrailingStep2);
|
|
||||||
CheckTimeBasedExits(InpMagicNumber2, InpMaxTradeDuration2, InpLossThreshold2);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for RSI signals
|
|
||||||
CheckRSISignals();
|
|
||||||
|
|
||||||
// Get current price
|
|
||||||
double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
|
||||||
double stopLoss = 0;
|
|
||||||
double takeProfit = 0;
|
|
||||||
|
|
||||||
// Strategy 1: Enter on RSI 50 touch after oversold/overbought
|
|
||||||
if(InpEnableStrategy1)
|
|
||||||
{
|
|
||||||
if(!IsWithinTradingHours())
|
|
||||||
{
|
|
||||||
MqlDateTime timeStruct;
|
|
||||||
TimeToStruct(TimeCurrent(), timeStruct);
|
|
||||||
Print("Strategy 1: Outside trading hours",
|
|
||||||
"\nCurrent Hour: ", timeStruct.hour,
|
|
||||||
"\nTrading Hours: ", InpStartHour, ":00 - ", InpEndHour, ":00");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for RSI-based exits for Strategy 1
|
|
||||||
if(InpEnableRSIExit1)
|
|
||||||
{
|
|
||||||
CheckRSIExits(InpMagicNumber1, true, InpRSIExitBuy1, InpRSIExitSell1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log current RSI state
|
|
||||||
Print("Strategy 1 Current State:",
|
|
||||||
"\nRSI: ", DoubleToString(lastRSI[0], 2),
|
|
||||||
"\nDistance from 50: ", DoubleToString(MathAbs(lastRSI[0] - 50), 2),
|
|
||||||
"\nWas Oversold: ", wasOversold ? "Yes" : "No",
|
|
||||||
"\nWas Overbought: ", wasOverbought ? "Yes" : "No",
|
|
||||||
"\nPosition Exists: ", PositionSelectByTicket(InpMagicNumber1) ? "Yes" : "No");
|
|
||||||
|
|
||||||
// Buy signal: RSI was oversold and now is near 50
|
|
||||||
if(wasOversold && MathAbs(lastRSI[0] - 50) <= InpRSI50Distance)
|
|
||||||
{
|
|
||||||
if(!PositionSelectByTicket(InpMagicNumber1))
|
|
||||||
{
|
|
||||||
stopLoss = InpEnableRSIExit1 && !InpUseSLTPWithRSI1 ? 0 : currentPrice - InpStopLoss1 * _Point;
|
|
||||||
takeProfit = InpEnableRSIExit1 && !InpUseSLTPWithRSI1 ? 0 : currentPrice + InpTakeProfit1 * _Point;
|
|
||||||
|
|
||||||
trade.SetExpertMagicNumber(InpMagicNumber1);
|
|
||||||
if(trade.Buy(InpLotSize1, _Symbol, 0, stopLoss, takeProfit, "RSI 50 Touch Buy"))
|
|
||||||
{
|
|
||||||
Print("Strategy 1 Buy trade executed: RSI was oversold and now near 50",
|
|
||||||
"\nRSI: ", DoubleToString(lastRSI[0], 2),
|
|
||||||
"\nDistance from 50: ", DoubleToString(MathAbs(lastRSI[0] - 50), 2),
|
|
||||||
"\nEntry Price: ", DoubleToString(currentPrice, _Digits),
|
|
||||||
"\nStop Loss: ", stopLoss == 0 ? "None" : DoubleToString(stopLoss, _Digits),
|
|
||||||
"\nTake Profit: ", takeProfit == 0 ? "None" : DoubleToString(takeProfit, _Digits));
|
|
||||||
wasOversold = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Print("Failed to execute Strategy 1 Buy trade",
|
|
||||||
"\nRSI: ", DoubleToString(lastRSI[0], 2),
|
|
||||||
"\nDistance from 50: ", DoubleToString(MathAbs(lastRSI[0] - 50), 2),
|
|
||||||
"\nError: ", GetLastError());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Print("Strategy 1 Buy signal detected but position already exists",
|
|
||||||
"\nRSI: ", DoubleToString(lastRSI[0], 2),
|
|
||||||
"\nDistance from 50: ", DoubleToString(MathAbs(lastRSI[0] - 50), 2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sell signal: RSI was overbought and now is near 50
|
|
||||||
if(wasOverbought && MathAbs(lastRSI[0] - 50) <= InpRSI50Distance)
|
|
||||||
{
|
|
||||||
if(!PositionSelectByTicket(InpMagicNumber1))
|
|
||||||
{
|
|
||||||
stopLoss = InpEnableRSIExit1 && !InpUseSLTPWithRSI1 ? 0 : currentPrice + InpStopLoss1 * _Point;
|
|
||||||
takeProfit = InpEnableRSIExit1 && !InpUseSLTPWithRSI1 ? 0 : currentPrice - InpTakeProfit1 * _Point;
|
|
||||||
|
|
||||||
trade.SetExpertMagicNumber(InpMagicNumber1);
|
|
||||||
if(trade.Sell(InpLotSize1, _Symbol, 0, stopLoss, takeProfit, "RSI 50 Touch Sell"))
|
|
||||||
{
|
|
||||||
Print("Strategy 1 Sell trade executed: RSI was overbought and now near 50",
|
|
||||||
"\nRSI: ", DoubleToString(lastRSI[0], 2),
|
|
||||||
"\nDistance from 50: ", DoubleToString(MathAbs(lastRSI[0] - 50), 2),
|
|
||||||
"\nEntry Price: ", DoubleToString(currentPrice, _Digits),
|
|
||||||
"\nStop Loss: ", stopLoss == 0 ? "None" : DoubleToString(stopLoss, _Digits),
|
|
||||||
"\nTake Profit: ", takeProfit == 0 ? "None" : DoubleToString(takeProfit, _Digits));
|
|
||||||
wasOverbought = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Print("Failed to execute Strategy 1 Sell trade",
|
|
||||||
"\nRSI: ", DoubleToString(lastRSI[0], 2),
|
|
||||||
"\nDistance from 50: ", DoubleToString(MathAbs(lastRSI[0] - 50), 2),
|
|
||||||
"\nError: ", GetLastError());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Print("Strategy 1 Sell signal detected but position already exists",
|
|
||||||
"\nRSI: ", DoubleToString(lastRSI[0], 2),
|
|
||||||
"\nDistance from 50: ", DoubleToString(MathAbs(lastRSI[0] - 50), 2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Strategy 2: Enter on RSI reversal from extremes
|
|
||||||
if(InpEnableStrategy2 && IsWithinTradingHours())
|
|
||||||
{
|
|
||||||
// Check for RSI-based exits for Strategy 2
|
|
||||||
if(InpEnableRSIExit2)
|
|
||||||
{
|
|
||||||
CheckRSIExits(InpMagicNumber2, true, InpRSIExitBuy2, InpRSIExitSell2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sell signal: RSI was overbought and now is moving down
|
|
||||||
if(wasOverbought && lastRSI[0] < lastRSI[1] && !PositionSelectByTicket(InpMagicNumber2))
|
|
||||||
{
|
|
||||||
stopLoss = InpEnableRSIExit2 && !InpUseSLTPWithRSI2 ? 0 : currentPrice + InpStopLoss2 * _Point;
|
|
||||||
takeProfit = InpEnableRSIExit2 && !InpUseSLTPWithRSI2 ? 0 : currentPrice - InpTakeProfit2 * _Point;
|
|
||||||
|
|
||||||
trade.SetExpertMagicNumber(InpMagicNumber2);
|
|
||||||
trade.Sell(InpLotSize2, _Symbol, 0, stopLoss, takeProfit, "RSI Reversal Sell");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Buy signal: RSI was oversold and now is moving up
|
|
||||||
if(wasOversold && lastRSI[0] > lastRSI[1] && !PositionSelectByTicket(InpMagicNumber2))
|
|
||||||
{
|
|
||||||
stopLoss = InpEnableRSIExit2 && !InpUseSLTPWithRSI2 ? 0 : currentPrice - InpStopLoss2 * _Point;
|
|
||||||
takeProfit = InpEnableRSIExit2 && !InpUseSLTPWithRSI2 ? 0 : currentPrice + InpTakeProfit2 * _Point;
|
|
||||||
|
|
||||||
trade.SetExpertMagicNumber(InpMagicNumber2);
|
|
||||||
trade.Buy(InpLotSize2, _Symbol, 0, stopLoss, takeProfit, "RSI Reversal Buy");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check trailing stops and time-based exits
|
|
||||||
if(InpEnableStrategy1)
|
|
||||||
{
|
|
||||||
CheckTrailingStop(InpMagicNumber1, InpTrailingStop1, InpTrailingStep1);
|
|
||||||
CheckTimeBasedExits(InpMagicNumber1, InpMaxTradeDuration1, InpLossThreshold1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(InpEnableStrategy2)
|
|
||||||
{
|
|
||||||
CheckTrailingStop(InpMagicNumber2, InpTrailingStop2, InpTrailingStep2);
|
|
||||||
CheckTimeBasedExits(InpMagicNumber2, InpMaxTradeDuration2, InpLossThreshold2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 282 KiB |
@@ -1,352 +0,0 @@
|
|||||||
//+------------------------------------------------------------------+
|
|
||||||
//| SmartRSI.mq5 |
|
|
||||||
//| Copyright 2024, MetaQuotes Ltd. |
|
|
||||||
//| https://www.mql5.com |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
#property copyright "Copyright 2024, MetaQuotes Ltd."
|
|
||||||
#property link "https://www.mql5.com"
|
|
||||||
#property version "1.00"
|
|
||||||
|
|
||||||
#include <Trade\Trade.mqh>
|
|
||||||
|
|
||||||
// Input parameters for RSI
|
|
||||||
input group "RSI Settings"
|
|
||||||
input int RSI_Period = 125; // RSI Period
|
|
||||||
input ENUM_APPLIED_PRICE RSI_Price = PRICE_MEDIAN; // RSI Applied Price
|
|
||||||
|
|
||||||
// Strategy Selection
|
|
||||||
input group "Strategy Selection"
|
|
||||||
input bool UseTrendFollowing = false; // Use Trend Following Strategy
|
|
||||||
input bool UseReversal = true; // Use Reversal Strategy
|
|
||||||
|
|
||||||
// Time Frames
|
|
||||||
input group "Time Frames"
|
|
||||||
input ENUM_TIMEFRAMES Trend_TimeFrame = PERIOD_H12; // Trend Following Time Frame
|
|
||||||
input ENUM_TIMEFRAMES Rev_TimeFrame = PERIOD_M6; // Reversal Time Frame
|
|
||||||
|
|
||||||
// Enum for RSI conditions
|
|
||||||
enum ENUM_RSI_CONDITION
|
|
||||||
{
|
|
||||||
RSI_BELOW_OVERSOLD, // RSI below oversold level
|
|
||||||
RSI_ABOVE_OVERBOUGHT, // RSI above overbought level
|
|
||||||
RSI_BELOW_MIDPOINT, // RSI below midpoint
|
|
||||||
RSI_ABOVE_MIDPOINT, // RSI above midpoint
|
|
||||||
RSI_CROSS_OVERSOLD, // RSI crosses below oversold
|
|
||||||
RSI_CROSS_OVERBOUGHT // RSI crosses above overbought
|
|
||||||
};
|
|
||||||
|
|
||||||
// Entry/Exit Conditions
|
|
||||||
input group "Entry/Exit Conditions"
|
|
||||||
input ENUM_RSI_CONDITION Trend_Entry_Condition = RSI_BELOW_OVERSOLD; // Trend Entry Condition
|
|
||||||
input ENUM_RSI_CONDITION Trend_Exit_Condition = RSI_BELOW_MIDPOINT; // Trend Exit Condition
|
|
||||||
input ENUM_RSI_CONDITION Rev_Entry_Condition = RSI_CROSS_OVERSOLD; // Reversal Entry Condition
|
|
||||||
input ENUM_RSI_CONDITION Rev_Exit_Condition = RSI_BELOW_MIDPOINT; // Reversal Exit Condition
|
|
||||||
|
|
||||||
// Trend Following Strategy Parameters
|
|
||||||
input group "Trend Following Strategy"
|
|
||||||
input double Trend_Overbought = 11; // Overbought level for trend following
|
|
||||||
input double Trend_Oversold = 26; // Oversold level for trend following
|
|
||||||
input double Trend_Exit_Long = 50; // Exit level for long positions
|
|
||||||
input double Trend_Exit_Short = 50; // Exit level for short positions
|
|
||||||
input double Trend_LotSize = 0.09; // Lot size for trend following
|
|
||||||
input int Trend_Magic = 12345; // Magic number for trend following
|
|
||||||
input bool Trend_CloseOpposite = false; // Close opposite trades on profit
|
|
||||||
input double Trend_ProfitToClose = 180; // Profit in points to close opposite trades
|
|
||||||
input int Trend_TimeToClose = 1; // Bars to wait before closing opposite trades
|
|
||||||
|
|
||||||
// Reversal Strategy Parameters
|
|
||||||
input group "Reversal Strategy"
|
|
||||||
input double Rev_Overbought = 60; // Overbought level for reversal
|
|
||||||
input double Rev_Oversold = 226; // Oversold level for reversal
|
|
||||||
input double Rev_Exit_Long = 50; // Exit level for long positions
|
|
||||||
input double Rev_Exit_Short = 50; // Exit level for short positions
|
|
||||||
input double Rev_LotSize = 0.06; // Lot size for reversal
|
|
||||||
input int Rev_Magic = 54321; // Magic number for reversal
|
|
||||||
input bool Rev_CloseOpposite = true; // Close opposite trades on profit
|
|
||||||
input double Rev_ProfitToClose = 105; // Profit in points to close opposite trades
|
|
||||||
input int Rev_TimeToClose = 5; // Bars to wait before closing opposite trades
|
|
||||||
|
|
||||||
// Indicator buffers
|
|
||||||
double trend_rsi_buffer[];
|
|
||||||
double rev_rsi_buffer[];
|
|
||||||
int trend_rsi_handle;
|
|
||||||
int rev_rsi_handle;
|
|
||||||
CTrade trade;
|
|
||||||
datetime last_trend_bar_time;
|
|
||||||
datetime last_rev_bar_time;
|
|
||||||
datetime trend_long_entry_time = 0;
|
|
||||||
datetime trend_short_entry_time = 0;
|
|
||||||
datetime rev_long_entry_time = 0;
|
|
||||||
datetime rev_short_entry_time = 0;
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Expert initialization function |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
int OnInit()
|
|
||||||
{
|
|
||||||
// Initialize RSI indicators
|
|
||||||
trend_rsi_handle = iRSI(_Symbol, Trend_TimeFrame, RSI_Period, RSI_Price);
|
|
||||||
rev_rsi_handle = iRSI(_Symbol, Rev_TimeFrame, RSI_Period, RSI_Price);
|
|
||||||
|
|
||||||
if(trend_rsi_handle == INVALID_HANDLE || rev_rsi_handle == INVALID_HANDLE)
|
|
||||||
{
|
|
||||||
Print("Failed to create RSI indicators");
|
|
||||||
return INIT_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set buffer size and series
|
|
||||||
ArraySetAsSeries(trend_rsi_buffer, true);
|
|
||||||
ArraySetAsSeries(rev_rsi_buffer, true);
|
|
||||||
|
|
||||||
// Initialize trade object
|
|
||||||
trade.SetExpertMagicNumber(Trend_Magic);
|
|
||||||
trade.SetMarginMode();
|
|
||||||
trade.SetTypeFillingBySymbol(_Symbol);
|
|
||||||
trade.SetDeviationInPoints(10);
|
|
||||||
|
|
||||||
// Initialize last bar times
|
|
||||||
last_trend_bar_time = 0;
|
|
||||||
last_rev_bar_time = 0;
|
|
||||||
|
|
||||||
return(INIT_SUCCEEDED);
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Expert deinitialization function |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void OnDeinit(const int reason)
|
|
||||||
{
|
|
||||||
if(trend_rsi_handle != INVALID_HANDLE)
|
|
||||||
IndicatorRelease(trend_rsi_handle);
|
|
||||||
if(rev_rsi_handle != INVALID_HANDLE)
|
|
||||||
IndicatorRelease(rev_rsi_handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Expert tick function |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void OnTick()
|
|
||||||
{
|
|
||||||
datetime current_trend_time = iTime(_Symbol, Trend_TimeFrame, 0);
|
|
||||||
datetime current_rev_time = iTime(_Symbol, Rev_TimeFrame, 0);
|
|
||||||
|
|
||||||
// Check if new bar has formed for trend following
|
|
||||||
if(current_trend_time != last_trend_bar_time)
|
|
||||||
{
|
|
||||||
last_trend_bar_time = current_trend_time;
|
|
||||||
|
|
||||||
// Update RSI values for trend following
|
|
||||||
if(CopyBuffer(trend_rsi_handle, 0, 0, 2, trend_rsi_buffer) <= 0)
|
|
||||||
{
|
|
||||||
Print("Failed to copy trend RSI buffer");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run trend following strategy if enabled
|
|
||||||
if(UseTrendFollowing)
|
|
||||||
CheckTrendFollowing();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if new bar has formed for reversal
|
|
||||||
if(current_rev_time != last_rev_bar_time)
|
|
||||||
{
|
|
||||||
last_rev_bar_time = current_rev_time;
|
|
||||||
|
|
||||||
// Update RSI values for reversal
|
|
||||||
if(CopyBuffer(rev_rsi_handle, 0, 0, 2, rev_rsi_buffer) <= 0)
|
|
||||||
{
|
|
||||||
Print("Failed to copy reversal RSI buffer");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run reversal strategy if enabled
|
|
||||||
if(UseReversal)
|
|
||||||
CheckReversal();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Check RSI Condition |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
bool CheckRSICondition(ENUM_RSI_CONDITION condition, double level, double &buffer[])
|
|
||||||
{
|
|
||||||
switch(condition)
|
|
||||||
{
|
|
||||||
case RSI_BELOW_OVERSOLD:
|
|
||||||
return buffer[0] < level;
|
|
||||||
case RSI_ABOVE_OVERBOUGHT:
|
|
||||||
return buffer[0] > level;
|
|
||||||
case RSI_BELOW_MIDPOINT:
|
|
||||||
return buffer[0] < 50;
|
|
||||||
case RSI_ABOVE_MIDPOINT:
|
|
||||||
return buffer[0] > 50;
|
|
||||||
case RSI_CROSS_OVERSOLD:
|
|
||||||
return buffer[0] < level && buffer[1] >= level;
|
|
||||||
case RSI_CROSS_OVERBOUGHT:
|
|
||||||
return buffer[0] > level && buffer[1] <= level;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Check Trend Following Strategy |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void CheckTrendFollowing()
|
|
||||||
{
|
|
||||||
// Check for existing positions
|
|
||||||
bool hasLong = PositionSelectByMagic(Trend_Magic, POSITION_TYPE_BUY);
|
|
||||||
bool hasShort = PositionSelectByMagic(Trend_Magic, POSITION_TYPE_SELL);
|
|
||||||
|
|
||||||
// Entry logic
|
|
||||||
if(!hasLong && !hasShort)
|
|
||||||
{
|
|
||||||
if(CheckRSICondition(Trend_Entry_Condition, Trend_Oversold, trend_rsi_buffer))
|
|
||||||
{
|
|
||||||
// Open short position
|
|
||||||
trade.SetExpertMagicNumber(Trend_Magic);
|
|
||||||
trade.Sell(Trend_LotSize, _Symbol, 0, 0, 0, "SmartRSI Trend");
|
|
||||||
trend_short_entry_time = TimeCurrent();
|
|
||||||
}
|
|
||||||
else if(CheckRSICondition(Trend_Entry_Condition, Trend_Overbought, trend_rsi_buffer))
|
|
||||||
{
|
|
||||||
// Open long position
|
|
||||||
trade.SetExpertMagicNumber(Trend_Magic);
|
|
||||||
trade.Buy(Trend_LotSize, _Symbol, 0, 0, 0, "SmartRSI Trend");
|
|
||||||
trend_long_entry_time = TimeCurrent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exit logic
|
|
||||||
if(hasLong && CheckRSICondition(Trend_Exit_Condition, Trend_Exit_Long, trend_rsi_buffer))
|
|
||||||
{
|
|
||||||
trade.SetExpertMagicNumber(Trend_Magic);
|
|
||||||
trade.PositionClose(_Symbol);
|
|
||||||
}
|
|
||||||
else if(hasShort && CheckRSICondition(Trend_Exit_Condition, Trend_Exit_Short, trend_rsi_buffer))
|
|
||||||
{
|
|
||||||
trade.SetExpertMagicNumber(Trend_Magic);
|
|
||||||
trade.PositionClose(_Symbol);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for opposite trade closing
|
|
||||||
if(Trend_CloseOpposite)
|
|
||||||
{
|
|
||||||
if(hasLong && (TimeCurrent() - trend_long_entry_time) >= Trend_TimeToClose * PeriodSeconds(Trend_TimeFrame))
|
|
||||||
{
|
|
||||||
double profit = PositionGetDouble(POSITION_PROFIT);
|
|
||||||
if(profit >= Trend_ProfitToClose * _Point)
|
|
||||||
{
|
|
||||||
// Close short position if exists
|
|
||||||
if(PositionSelectByMagic(Trend_Magic, POSITION_TYPE_SELL))
|
|
||||||
{
|
|
||||||
trade.SetExpertMagicNumber(Trend_Magic);
|
|
||||||
trade.PositionClose(_Symbol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(hasShort && (TimeCurrent() - trend_short_entry_time) >= Trend_TimeToClose * PeriodSeconds(Trend_TimeFrame))
|
|
||||||
{
|
|
||||||
double profit = PositionGetDouble(POSITION_PROFIT);
|
|
||||||
if(profit >= Trend_ProfitToClose * _Point)
|
|
||||||
{
|
|
||||||
// Close long position if exists
|
|
||||||
if(PositionSelectByMagic(Trend_Magic, POSITION_TYPE_BUY))
|
|
||||||
{
|
|
||||||
trade.SetExpertMagicNumber(Trend_Magic);
|
|
||||||
trade.PositionClose(_Symbol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Check Reversal Strategy |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void CheckReversal()
|
|
||||||
{
|
|
||||||
// Check for existing positions
|
|
||||||
bool hasLong = PositionSelectByMagic(Rev_Magic, POSITION_TYPE_BUY);
|
|
||||||
bool hasShort = PositionSelectByMagic(Rev_Magic, POSITION_TYPE_SELL);
|
|
||||||
|
|
||||||
// Entry logic
|
|
||||||
if(!hasLong && !hasShort)
|
|
||||||
{
|
|
||||||
if(CheckRSICondition(Rev_Entry_Condition, Rev_Oversold, rev_rsi_buffer))
|
|
||||||
{
|
|
||||||
// Open long position
|
|
||||||
trade.SetExpertMagicNumber(Rev_Magic);
|
|
||||||
trade.Buy(Rev_LotSize, _Symbol, 0, 0, 0, "SmartRSI Reversal");
|
|
||||||
rev_long_entry_time = TimeCurrent();
|
|
||||||
}
|
|
||||||
else if(CheckRSICondition(Rev_Entry_Condition, Rev_Overbought, rev_rsi_buffer))
|
|
||||||
{
|
|
||||||
// Open short position
|
|
||||||
trade.SetExpertMagicNumber(Rev_Magic);
|
|
||||||
trade.Sell(Rev_LotSize, _Symbol, 0, 0, 0, "SmartRSI Reversal");
|
|
||||||
rev_short_entry_time = TimeCurrent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exit logic
|
|
||||||
if(hasLong && CheckRSICondition(Rev_Exit_Condition, Rev_Exit_Long, rev_rsi_buffer))
|
|
||||||
{
|
|
||||||
trade.SetExpertMagicNumber(Rev_Magic);
|
|
||||||
trade.PositionClose(_Symbol);
|
|
||||||
}
|
|
||||||
else if(hasShort && CheckRSICondition(Rev_Exit_Condition, Rev_Exit_Short, rev_rsi_buffer))
|
|
||||||
{
|
|
||||||
trade.SetExpertMagicNumber(Rev_Magic);
|
|
||||||
trade.PositionClose(_Symbol);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for opposite trade closing
|
|
||||||
if(Rev_CloseOpposite)
|
|
||||||
{
|
|
||||||
if(hasLong && (TimeCurrent() - rev_long_entry_time) >= Rev_TimeToClose * PeriodSeconds(Rev_TimeFrame))
|
|
||||||
{
|
|
||||||
double profit = PositionGetDouble(POSITION_PROFIT);
|
|
||||||
if(profit >= Rev_ProfitToClose * _Point)
|
|
||||||
{
|
|
||||||
// Close short position if exists
|
|
||||||
if(PositionSelectByMagic(Rev_Magic, POSITION_TYPE_SELL))
|
|
||||||
{
|
|
||||||
trade.SetExpertMagicNumber(Rev_Magic);
|
|
||||||
trade.PositionClose(_Symbol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(hasShort && (TimeCurrent() - rev_short_entry_time) >= Rev_TimeToClose * PeriodSeconds(Rev_TimeFrame))
|
|
||||||
{
|
|
||||||
double profit = PositionGetDouble(POSITION_PROFIT);
|
|
||||||
if(profit >= Rev_ProfitToClose * _Point)
|
|
||||||
{
|
|
||||||
// Close long position if exists
|
|
||||||
if(PositionSelectByMagic(Rev_Magic, POSITION_TYPE_BUY))
|
|
||||||
{
|
|
||||||
trade.SetExpertMagicNumber(Rev_Magic);
|
|
||||||
trade.PositionClose(_Symbol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Position Select By Magic |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
bool PositionSelectByMagic(int magic, ENUM_POSITION_TYPE posType)
|
|
||||||
{
|
|
||||||
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
if(PositionGetTicket(i))
|
|
||||||
{
|
|
||||||
if(PositionGetInteger(POSITION_MAGIC) == magic &&
|
|
||||||
PositionGetInteger(POSITION_TYPE) == posType)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 290 KiB |
@@ -1,325 +0,0 @@
|
|||||||
//+------------------------------------------------------------------+
|
|
||||||
//| SmartRSI.mq5 |
|
|
||||||
//| Copyright 2024, MetaQuotes Ltd. |
|
|
||||||
//| https://www.mql5.com |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
#property copyright "Copyright 2024, MetaQuotes Ltd."
|
|
||||||
#property link "https://www.mql5.com"
|
|
||||||
#property version "1.00"
|
|
||||||
|
|
||||||
#include <Trade\Trade.mqh>
|
|
||||||
|
|
||||||
// Input parameters for RSI
|
|
||||||
input group "RSI Settings"
|
|
||||||
input int RSI_Period = 89; // RSI Period
|
|
||||||
input ENUM_APPLIED_PRICE RSI_Price = PRICE_TYPICAL; // RSI Applied Price
|
|
||||||
|
|
||||||
// Strategy Selection
|
|
||||||
input group "Strategy Selection"
|
|
||||||
input bool UseTrendFollowing = true; // Use Trend Following Strategy
|
|
||||||
input bool UseReversal = false; // Use Reversal Strategy
|
|
||||||
|
|
||||||
// Enum for RSI conditions
|
|
||||||
enum ENUM_RSI_CONDITION
|
|
||||||
{
|
|
||||||
RSI_BELOW_OVERSOLD, // RSI below oversold level
|
|
||||||
RSI_ABOVE_OVERBOUGHT, // RSI above overbought level
|
|
||||||
RSI_BELOW_MIDPOINT, // RSI below midpoint
|
|
||||||
RSI_ABOVE_MIDPOINT, // RSI above midpoint
|
|
||||||
RSI_CROSS_OVERSOLD, // RSI crosses below oversold
|
|
||||||
RSI_CROSS_OVERBOUGHT // RSI crosses above overbought
|
|
||||||
};
|
|
||||||
|
|
||||||
// Entry/Exit Conditions
|
|
||||||
input group "Entry/Exit Conditions"
|
|
||||||
input ENUM_RSI_CONDITION Trend_Entry_Condition = RSI_BELOW_OVERSOLD; // Trend Entry Condition
|
|
||||||
input ENUM_RSI_CONDITION Trend_Exit_Condition = RSI_ABOVE_MIDPOINT; // Trend Exit Condition
|
|
||||||
input ENUM_RSI_CONDITION Rev_Entry_Condition = RSI_BELOW_OVERSOLD; // Reversal Entry Condition
|
|
||||||
input ENUM_RSI_CONDITION Rev_Exit_Condition = RSI_ABOVE_MIDPOINT; // Reversal Exit Condition
|
|
||||||
|
|
||||||
// Trend Following Strategy Parameters
|
|
||||||
input group "Trend Following Strategy"
|
|
||||||
input double Trend_Overbought = 51; // Overbought level for trend following
|
|
||||||
input double Trend_Oversold = 30; // Oversold level for trend following
|
|
||||||
input double Trend_Exit_Long = 50; // Exit level for long positions
|
|
||||||
input double Trend_Exit_Short = 50; // Exit level for short positions
|
|
||||||
input double Trend_LotSize = 0.1; // Lot size for trend following
|
|
||||||
input int Trend_Magic = 12345; // Magic number for trend following
|
|
||||||
input bool Trend_CloseOpposite = true; // Close opposite trades on profit
|
|
||||||
input double Trend_ProfitToClose = 15; // Profit in points to close opposite trades
|
|
||||||
input int Trend_TimeToClose = 9; // Bars to wait before closing opposite trades
|
|
||||||
|
|
||||||
// Reversal Strategy Parameters
|
|
||||||
input group "Reversal Strategy"
|
|
||||||
input double Rev_Overbought = 70; // Overbought level for reversal
|
|
||||||
input double Rev_Oversold = 30; // Oversold level for reversal
|
|
||||||
input double Rev_Exit_Long = 50; // Exit level for long positions
|
|
||||||
input double Rev_Exit_Short = 50; // Exit level for short positions
|
|
||||||
input double Rev_LotSize = 0.1; // Lot size for reversal
|
|
||||||
input int Rev_Magic = 54321; // Magic number for reversal
|
|
||||||
input bool Rev_CloseOpposite = true; // Close opposite trades on profit
|
|
||||||
input double Rev_ProfitToClose = 50; // Profit in points to close opposite trades
|
|
||||||
input int Rev_TimeToClose = 5; // Bars to wait before closing opposite trades
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Indicator buffers
|
|
||||||
double rsi_buffer[];
|
|
||||||
int rsi_handle;
|
|
||||||
CTrade trade;
|
|
||||||
datetime last_bar_time;
|
|
||||||
datetime trend_long_entry_time = 0;
|
|
||||||
datetime trend_short_entry_time = 0;
|
|
||||||
datetime rev_long_entry_time = 0;
|
|
||||||
datetime rev_short_entry_time = 0;
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Expert initialization function |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
int OnInit()
|
|
||||||
{
|
|
||||||
// Initialize RSI indicator
|
|
||||||
rsi_handle = iRSI(_Symbol, PERIOD_CURRENT, RSI_Period, RSI_Price);
|
|
||||||
if(rsi_handle == INVALID_HANDLE)
|
|
||||||
{
|
|
||||||
Print("Failed to create RSI indicator");
|
|
||||||
return INIT_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set buffer size and series
|
|
||||||
ArraySetAsSeries(rsi_buffer, true);
|
|
||||||
|
|
||||||
// Initialize trade object
|
|
||||||
trade.SetExpertMagicNumber(Trend_Magic);
|
|
||||||
trade.SetMarginMode();
|
|
||||||
trade.SetTypeFillingBySymbol(_Symbol);
|
|
||||||
trade.SetDeviationInPoints(10);
|
|
||||||
|
|
||||||
// Initialize last bar time
|
|
||||||
last_bar_time = 0;
|
|
||||||
|
|
||||||
return(INIT_SUCCEEDED);
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Expert deinitialization function |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void OnDeinit(const int reason)
|
|
||||||
{
|
|
||||||
if(rsi_handle != INVALID_HANDLE)
|
|
||||||
IndicatorRelease(rsi_handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Expert tick function |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void OnTick()
|
|
||||||
{
|
|
||||||
datetime current_time = iTime(_Symbol, PERIOD_CURRENT, 0);
|
|
||||||
|
|
||||||
// Check if new bar has formed
|
|
||||||
if(current_time != last_bar_time)
|
|
||||||
{
|
|
||||||
last_bar_time = current_time;
|
|
||||||
|
|
||||||
// Update RSI values
|
|
||||||
if(CopyBuffer(rsi_handle, 0, 0, 2, rsi_buffer) <= 0)
|
|
||||||
{
|
|
||||||
Print("Failed to copy RSI buffer");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run strategies if enabled
|
|
||||||
if(UseTrendFollowing)
|
|
||||||
CheckTrendFollowing();
|
|
||||||
|
|
||||||
if(UseReversal)
|
|
||||||
CheckReversal();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Check RSI Condition |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
bool CheckRSICondition(ENUM_RSI_CONDITION condition, double level)
|
|
||||||
{
|
|
||||||
switch(condition)
|
|
||||||
{
|
|
||||||
case RSI_BELOW_OVERSOLD:
|
|
||||||
return rsi_buffer[0] < level;
|
|
||||||
case RSI_ABOVE_OVERBOUGHT:
|
|
||||||
return rsi_buffer[0] > level;
|
|
||||||
case RSI_BELOW_MIDPOINT:
|
|
||||||
return rsi_buffer[0] < 50;
|
|
||||||
case RSI_ABOVE_MIDPOINT:
|
|
||||||
return rsi_buffer[0] > 50;
|
|
||||||
case RSI_CROSS_OVERSOLD:
|
|
||||||
return rsi_buffer[0] < level && rsi_buffer[1] >= level;
|
|
||||||
case RSI_CROSS_OVERBOUGHT:
|
|
||||||
return rsi_buffer[0] > level && rsi_buffer[1] <= level;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Check Trend Following Strategy |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void CheckTrendFollowing()
|
|
||||||
{
|
|
||||||
// Check for existing positions
|
|
||||||
bool hasLong = PositionSelectByMagic(Trend_Magic, POSITION_TYPE_BUY);
|
|
||||||
bool hasShort = PositionSelectByMagic(Trend_Magic, POSITION_TYPE_SELL);
|
|
||||||
|
|
||||||
// Entry logic
|
|
||||||
if(!hasLong && !hasShort)
|
|
||||||
{
|
|
||||||
if(CheckRSICondition(Trend_Entry_Condition, Trend_Oversold))
|
|
||||||
{
|
|
||||||
// Open short position
|
|
||||||
trade.SetExpertMagicNumber(Trend_Magic);
|
|
||||||
trade.Sell(Trend_LotSize, _Symbol, 0, 0, 0, "SmartRSI Trend");
|
|
||||||
trend_short_entry_time = TimeCurrent();
|
|
||||||
}
|
|
||||||
else if(CheckRSICondition(Trend_Entry_Condition, Trend_Overbought))
|
|
||||||
{
|
|
||||||
// Open long position
|
|
||||||
trade.SetExpertMagicNumber(Trend_Magic);
|
|
||||||
trade.Buy(Trend_LotSize, _Symbol, 0, 0, 0, "SmartRSI Trend");
|
|
||||||
trend_long_entry_time = TimeCurrent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exit logic
|
|
||||||
if(hasLong && CheckRSICondition(Trend_Exit_Condition, Trend_Exit_Long))
|
|
||||||
{
|
|
||||||
trade.SetExpertMagicNumber(Trend_Magic);
|
|
||||||
trade.PositionClose(_Symbol);
|
|
||||||
}
|
|
||||||
else if(hasShort && CheckRSICondition(Trend_Exit_Condition, Trend_Exit_Short))
|
|
||||||
{
|
|
||||||
trade.SetExpertMagicNumber(Trend_Magic);
|
|
||||||
trade.PositionClose(_Symbol);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for opposite trade closing
|
|
||||||
if(Trend_CloseOpposite)
|
|
||||||
{
|
|
||||||
if(hasLong && (TimeCurrent() - trend_long_entry_time) >= Trend_TimeToClose * PeriodSeconds(PERIOD_CURRENT))
|
|
||||||
{
|
|
||||||
double profit = PositionGetDouble(POSITION_PROFIT);
|
|
||||||
if(profit >= Trend_ProfitToClose * _Point)
|
|
||||||
{
|
|
||||||
// Close short position if exists
|
|
||||||
if(PositionSelectByMagic(Trend_Magic, POSITION_TYPE_SELL))
|
|
||||||
{
|
|
||||||
trade.SetExpertMagicNumber(Trend_Magic);
|
|
||||||
trade.PositionClose(_Symbol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(hasShort && (TimeCurrent() - trend_short_entry_time) >= Trend_TimeToClose * PeriodSeconds(PERIOD_CURRENT))
|
|
||||||
{
|
|
||||||
double profit = PositionGetDouble(POSITION_PROFIT);
|
|
||||||
if(profit >= Trend_ProfitToClose * _Point)
|
|
||||||
{
|
|
||||||
// Close long position if exists
|
|
||||||
if(PositionSelectByMagic(Trend_Magic, POSITION_TYPE_BUY))
|
|
||||||
{
|
|
||||||
trade.SetExpertMagicNumber(Trend_Magic);
|
|
||||||
trade.PositionClose(_Symbol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Check Reversal Strategy |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
void CheckReversal()
|
|
||||||
{
|
|
||||||
// Check for existing positions
|
|
||||||
bool hasLong = PositionSelectByMagic(Rev_Magic, POSITION_TYPE_BUY);
|
|
||||||
bool hasShort = PositionSelectByMagic(Rev_Magic, POSITION_TYPE_SELL);
|
|
||||||
|
|
||||||
// Entry logic
|
|
||||||
if(!hasLong && !hasShort)
|
|
||||||
{
|
|
||||||
if(CheckRSICondition(Rev_Entry_Condition, Rev_Oversold))
|
|
||||||
{
|
|
||||||
// Open long position
|
|
||||||
trade.SetExpertMagicNumber(Rev_Magic);
|
|
||||||
trade.Buy(Rev_LotSize, _Symbol, 0, 0, 0, "SmartRSI Reversal");
|
|
||||||
rev_long_entry_time = TimeCurrent();
|
|
||||||
}
|
|
||||||
else if(CheckRSICondition(Rev_Entry_Condition, Rev_Overbought))
|
|
||||||
{
|
|
||||||
// Open short position
|
|
||||||
trade.SetExpertMagicNumber(Rev_Magic);
|
|
||||||
trade.Sell(Rev_LotSize, _Symbol, 0, 0, 0, "SmartRSI Reversal");
|
|
||||||
rev_short_entry_time = TimeCurrent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exit logic
|
|
||||||
if(hasLong && CheckRSICondition(Rev_Exit_Condition, Rev_Exit_Long))
|
|
||||||
{
|
|
||||||
trade.SetExpertMagicNumber(Rev_Magic);
|
|
||||||
trade.PositionClose(_Symbol);
|
|
||||||
}
|
|
||||||
else if(hasShort && CheckRSICondition(Rev_Exit_Condition, Rev_Exit_Short))
|
|
||||||
{
|
|
||||||
trade.SetExpertMagicNumber(Rev_Magic);
|
|
||||||
trade.PositionClose(_Symbol);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for opposite trade closing
|
|
||||||
if(Rev_CloseOpposite)
|
|
||||||
{
|
|
||||||
if(hasLong && (TimeCurrent() - rev_long_entry_time) >= Rev_TimeToClose * PeriodSeconds(PERIOD_CURRENT))
|
|
||||||
{
|
|
||||||
double profit = PositionGetDouble(POSITION_PROFIT);
|
|
||||||
if(profit >= Rev_ProfitToClose * _Point)
|
|
||||||
{
|
|
||||||
// Close short position if exists
|
|
||||||
if(PositionSelectByMagic(Rev_Magic, POSITION_TYPE_SELL))
|
|
||||||
{
|
|
||||||
trade.SetExpertMagicNumber(Rev_Magic);
|
|
||||||
trade.PositionClose(_Symbol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(hasShort && (TimeCurrent() - rev_short_entry_time) >= Rev_TimeToClose * PeriodSeconds(PERIOD_CURRENT))
|
|
||||||
{
|
|
||||||
double profit = PositionGetDouble(POSITION_PROFIT);
|
|
||||||
if(profit >= Rev_ProfitToClose * _Point)
|
|
||||||
{
|
|
||||||
// Close long position if exists
|
|
||||||
if(PositionSelectByMagic(Rev_Magic, POSITION_TYPE_BUY))
|
|
||||||
{
|
|
||||||
trade.SetExpertMagicNumber(Rev_Magic);
|
|
||||||
trade.PositionClose(_Symbol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
//| Position Select By Magic |
|
|
||||||
//+------------------------------------------------------------------+
|
|
||||||
bool PositionSelectByMagic(int magic, ENUM_POSITION_TYPE posType)
|
|
||||||
{
|
|
||||||
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
if(PositionGetTicket(i))
|
|
||||||
{
|
|
||||||
if(PositionGetInteger(POSITION_MAGIC) == magic &&
|
|
||||||
PositionGetInteger(POSITION_TYPE) == posType)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 300 KiB |