@@ -1,3 +1,18 @@
|
|||||||
|
# Table of Contents
|
||||||
|
- [Table of Contents](#table-of-contents)
|
||||||
|
- [Profitable Expert Advisors Collection](#profitable-expert-advisors-collection)
|
||||||
|
- [Project Overview](#project-overview)
|
||||||
|
- [Available Expert Advisors](#available-expert-advisors)
|
||||||
|
- [1. RSI Divergence Rebound](#1-rsi-divergence-rebound)
|
||||||
|
- [2. EMA Crossover Skirmish](#2-ema-crossover-skirmish)
|
||||||
|
- [3. RSI Divergence Extrema AUDUSD](#3-rsi-divergence-extrema-audusd)
|
||||||
|
- [4. RSI Divergence Extrema EURUSD](#4-rsi-divergence-extrema-eurusd)
|
||||||
|
- [Technical Details](#technical-details)
|
||||||
|
- [Requirements](#requirements)
|
||||||
|
- [Installation](#installation)
|
||||||
|
- [Disclaimer](#disclaimer)
|
||||||
|
|
||||||
|
|
||||||
# Profitable Expert Advisors Collection
|
# Profitable Expert Advisors Collection
|
||||||
|
|
||||||
## Project Overview
|
## Project Overview
|
||||||
@@ -73,9 +88,6 @@ A strategy that combines RSI (Relative Strength Index) divergence detection with
|
|||||||
**Balance Sheet (2021-2025):**
|
**Balance Sheet (2021-2025):**
|
||||||

|

|
||||||
|
|
||||||
**Additional Test Results (2008):**
|
|
||||||

|
|
||||||
|
|
||||||
### 2. EMA Crossover Skirmish
|
### 2. EMA Crossover Skirmish
|
||||||
A strategy that uses Exponential Moving Average (EMA) crossovers with advanced scoring and position management.
|
A strategy that uses Exponential Moving Average (EMA) crossovers with advanced scoring and position management.
|
||||||
|
|
||||||
@@ -139,10 +151,8 @@ A strategy that uses Exponential Moving Average (EMA) crossovers with advanced s
|
|||||||
**Balance Sheet (2021-2025):**
|
**Balance Sheet (2021-2025):**
|
||||||

|

|
||||||
|
|
||||||
**Additional Test Results (2008):**
|
|
||||||

|
|
||||||
|
|
||||||
### 3. RSI Divergence Extrema
|
### 3. RSI Divergence Extrema AUDUSD
|
||||||
|
|
||||||
A strategy that combines RSI divergence with extreme price points detection for enhanced market reversal signals.
|
A strategy that combines RSI divergence with extreme price points detection for enhanced market reversal signals.
|
||||||
|
|
||||||
@@ -206,7 +216,77 @@ A strategy that combines RSI divergence with extreme price points detection for
|
|||||||
| Equity Drawdown Relative | 5.54% ($42.06) |
|
| Equity Drawdown Relative | 5.54% ($42.06) |
|
||||||
|
|
||||||
**Balance Sheet (2021-2025):**
|
**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):**
|
||||||
|

|
||||||
|
|
||||||
## Technical Details
|
## Technical Details
|
||||||
Each EA is implemented in MQL5 and includes:
|
Each EA is implemented in MQL5 and includes:
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 246 KiB After Width: | Height: | Size: 246 KiB |
@@ -0,0 +1,655 @@
|
|||||||
|
//+------------------------------------------------------------------+
|
||||||
|
//| 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(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();
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
//+------------------------------------------------------------------+
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 255 KiB |
Reference in New Issue
Block a user