Merge pull request #12 from zhutoutoutousan/develop

Update BTC strategy
This commit is contained in:
zhutoutoutousan
2025-04-22 11:01:34 +08:00
committed by GitHub
3 changed files with 628 additions and 0 deletions
+42
View File
@@ -7,6 +7,7 @@
- [2. RSI MidPoint Hijack XAU/USD](#2-rsi-midpoint-hijack-xauusd)
- [3. RSI Reversal Asian EUR/USD](#3-rsi-reversal-asian-eurusd)
- [4. RSI CrossOver Reversal XAU/USD](#4-rsi-crossover-reversal-xauusd)
- [5. RSI Follow Reverse EMA CrossOver BTC/USD](#5-rsi-follow-reverse-ema-crossover-btcusd)
- [Strategy Rationale](#strategy-rationale)
- [RSI Reversal Strategy](#rsi-reversal-strategy)
- [RSI MidPoint Hijack Strategy](#rsi-midpoint-hijack-strategy)
@@ -141,6 +142,47 @@ TrailingStop = 295; // Trailing stop in pips
<img src="RSICrossOverReversalXAUUSD/test-balance.jpg" alt="RSI CrossOver Reversal XAU/USD Test Balance" width="600"/>
</div>
### 5. RSI Follow Reverse EMA CrossOver BTC/USD
- **Strategy**: Multi-strategy approach combining RSI Follow, RSI Reverse, and EMA crossovers
- **Key Features**:
- Implements three distinct strategies:
1. RSI Follow Strategy
2. RSI Reverse Strategy
3. EMA Cross Strategy
- Optimized for Bitcoin (BTC/USD) trading
- Includes strategy locking mechanism to protect profits
- Features cooldown periods after losses
- Time-based trading windows for each strategy
- Adaptive position sizing based on volatility
**Core Parameters:**
```mql5
// RSI Follow Strategy
InpRSIPeriod = 14; // RSI Period
InpRSIOverbought = 70; // RSI Overbought Level
InpRSIOversold = 30; // RSI Oversold Level
// RSI Reverse Strategy
InpRSIReversePeriod = 14; // RSI Period
InpRSIReverseOverbought = 80; // RSI Overbought Level
InpRSIReverseOversold = 20; // RSI Oversold Level
// EMA Settings
InpEMAPeriod = 200; // EMA Period
InpEMASlopeThreshold = 0.1; // EMA Slope Threshold
InpEMADistanceThreshold = 100; // EMA Distance Threshold
// Strategy Management
InpEnableStrategyLock = true; // Enable Strategy Lock
InpLockProfitThreshold = 1000; // Lock Profit Threshold (pips)
InpCooldownPeriod = 24; // Cooldown Period in hours
```
**Test Balance Results:**
<div align="center">
<img src="RSIFollowReverseEMACrossOverBTCUSD/test-balance.jpg" alt="RSI Follow Reverse EMA CrossOver BTC/USD Test Balance" width="600"/>
</div>
## Strategy Rationale
### RSI Reversal Strategy
+586
View File
@@ -0,0 +1,586 @@
//+------------------------------------------------------------------+
//| RSIFollowReverseEMACrossOver.mq5 |
//| Copyright 2024, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include <Trade\Trade.mqh>
#include <Trade\PositionInfo.mqh>
// Input Parameters
input group "General Settings"
input ENUM_TIMEFRAMES InpTimeframe = PERIOD_CURRENT; // Trading Timeframe
input double InpLotSize = 0.01; // Lot Size
input int InpMagicNumberRSIFollow = 1001; // Magic Number RSI Follow
input int InpMagicNumberRSIReverse = 1002;// Magic Number RSI Reverse
input int InpMagicNumberEMACross = 1003; // Magic Number EMA Cross
input group "Strategy Switches"
input bool InpEnableRSIFollow = true; // Enable RSI Follow Strategy
input bool InpEnableRSIReverse = true; // Enable RSI Reverse Strategy
input bool InpEnableEMACross = true; // Enable EMA Cross Strategy
input bool InpEnableStrategyLock = false; // Enable Strategy Lock
input double InpLockProfitThreshold = 120.0; // Lock Profit Threshold (pips)
input bool InpCloseOppositeTrades = true; // Close Opposite Trades When Profiting
input group "RSI Follow Strategy"
input int InpRSIPeriod = 49; // RSI Period
input int InpRSIOverbought = 81; // RSI Overbought Level
input int InpRSIOversold = 41; // RSI Oversold Level
input int InpRSIExitLevel = 48; // RSI Exit Level
input int InpRSIFollowStartHour = 24; // RSI Follow Start Hour (0-23)
input int InpRSIFollowEndHour = 8; // RSI Follow End Hour (0-23)
input bool InpRSIFollowCloseOutsideHours = false; // Close trades outside trading hours
input group "RSI Reverse Strategy"
input int InpRSIReversePeriod = 159; // RSI Period
input int InpRSIReverseOverbought = 51; // RSI Overbought Level
input int InpRSIReverseOversold = 49; // RSI Oversold Level
input int InpRSIReverseCrossLevel = 54; // RSI Cross Level
input int InpRSIReverseExitLevel = 49; // RSI Exit Level
input int InpRSIReverseStartHour = 12; // RSI Reverse Start Hour (0-23)
input int InpRSIReverseEndHour = 22; // RSI Reverse End Hour (0-23)
input bool InpRSIReverseCloseOutsideHours = false; // Close trades outside trading hours
input int InpRSIReverseCooldownBars = 11; // RSI Reverse Cooldown (bars)
input bool InpRSIReverseCooldownOnLoss = true; // Apply cooldown only on loss
input group "EMA Cross Strategy"
input int InpEMAPeriod = 175; // EMA Period
input int InpEMACrossStartHour = 22; // EMA Cross Start Hour (0-23)
input int InpEMACrossEndHour = 12; // EMA Cross End Hour (0-23)
input bool InpEMACrossCloseOutsideHours = false; // Close trades outside trading hours
input bool InpUseEMADistanceEntry = true; // Use EMA Distance Entry
input double InpEMADistancePips = 8440.0; // EMA Distance Threshold (pips)
input int InpEMADistancePeriod = 30; // EMA Distance Period (bars)
// Global Variables
int rsiHandle;
int rsiReverseHandle;
int emaHandle;
bool rsiOverbought = false;
bool rsiOversold = false;
bool rsiReverseOverbought = false;
bool rsiReverseOversold = false;
CTrade trade;
CPositionInfo positionInfo;
bool emaCrossBuySignal = false;
bool emaCrossSellSignal = false;
int emaCrossSignalBar = 0;
datetime lastBarTime = 0;
datetime rsiReverseLastCloseTime = 0;
bool rsiReverseInCooldown = false;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Initialize indicators
rsiHandle = iRSI(_Symbol, InpTimeframe, InpRSIPeriod, PRICE_CLOSE);
rsiReverseHandle = iRSI(_Symbol, InpTimeframe, InpRSIReversePeriod, PRICE_CLOSE);
emaHandle = iMA(_Symbol, InpTimeframe, InpEMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
if(rsiHandle == INVALID_HANDLE || rsiReverseHandle == INVALID_HANDLE || emaHandle == INVALID_HANDLE)
{
Print("Error creating indicators");
return INIT_FAILED;
}
// Initialize trade settings
trade.SetExpertMagicNumber(InpMagicNumberRSIFollow);
trade.SetMarginMode();
trade.SetTypeFillingBySymbol(_Symbol);
trade.SetDeviationInPoints(10);
// Initialize last bar time
datetime time[];
if(CopyTime(_Symbol, InpTimeframe, 0, 1, time) > 0)
{
lastBarTime = time[0];
}
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Check if new bar has formed |
//+------------------------------------------------------------------+
bool IsNewBar()
{
datetime time[];
if(CopyTime(_Symbol, InpTimeframe, 0, 1, time) > 0)
{
if(time[0] != lastBarTime)
{
lastBarTime = time[0];
return true;
}
}
return false;
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// Release indicator handles
IndicatorRelease(rsiHandle);
IndicatorRelease(rsiReverseHandle);
IndicatorRelease(emaHandle);
}
//+------------------------------------------------------------------+
//| Check if current time is within trading hours |
//+------------------------------------------------------------------+
bool IsWithinTradingHours(int startHour, int endHour)
{
MqlDateTime currentTime;
TimeToStruct(TimeCurrent(), currentTime);
if(startHour <= endHour)
{
return (currentTime.hour >= startHour && currentTime.hour < endHour);
}
else
{
return (currentTime.hour >= startHour || currentTime.hour < endHour);
}
}
//+------------------------------------------------------------------+
//| Check if position exists for given magic number |
//+------------------------------------------------------------------+
bool HasPosition(int magic)
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(positionInfo.SelectByIndex(i))
{
if(positionInfo.Magic() == magic)
return true;
}
}
return false;
}
//+------------------------------------------------------------------+
//| Check if any strategy has profitable position |
//+------------------------------------------------------------------+
bool HasProfitablePosition(int excludeMagic)
{
bool hasProfitable = false;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(positionInfo.SelectByIndex(i))
{
if(positionInfo.Magic() != excludeMagic)
{
double profit = positionInfo.Profit();
if(profit > InpLockProfitThreshold * _Point)
{
hasProfitable = true;
// If enabled, close opposite trades
if(InpCloseOppositeTrades)
{
// Check if this is an opposite trade to the excluded magic number
if((excludeMagic == InpMagicNumberRSIFollow && positionInfo.Magic() == InpMagicNumberRSIReverse) ||
(excludeMagic == InpMagicNumberRSIReverse && positionInfo.Magic() == InpMagicNumberRSIFollow) ||
(excludeMagic == InpMagicNumberEMACross && (positionInfo.Magic() == InpMagicNumberRSIReverse || positionInfo.Magic() == InpMagicNumberRSIFollow)) ||
((excludeMagic == InpMagicNumberRSIFollow || excludeMagic == InpMagicNumberRSIReverse) && positionInfo.Magic() == InpMagicNumberEMACross))
{
ClosePosition(positionInfo.Magic());
}
}
}
}
}
}
return hasProfitable;
}
//+------------------------------------------------------------------+
//| Check for RSI Follow Strategy signals |
//+------------------------------------------------------------------+
void CheckRSIFollowStrategy()
{
// Check if within trading hours
if(!IsWithinTradingHours(InpRSIFollowStartHour, InpRSIFollowEndHour))
{
if(InpRSIFollowCloseOutsideHours)
{
if(HasPosition(InpMagicNumberRSIFollow))
{
ClosePosition(InpMagicNumberRSIFollow);
}
}
return;
}
// Check strategy lock
if(InpEnableStrategyLock && HasProfitablePosition(InpMagicNumberRSIFollow))
return;
double rsi[];
ArraySetAsSeries(rsi, true);
CopyBuffer(rsiHandle, 0, 0, 3, rsi);
if(ArraySize(rsi) < 3) return;
// Check for overbought condition
if(rsi[1] > InpRSIOverbought)
rsiOverbought = true;
else if(rsi[1] < InpRSIOversold)
rsiOversold = true;
// Check for entry signals
if(rsiOverbought && rsi[1] < rsi[0] && rsi[1] < InpRSIExitLevel)
{
// Sell signal
if(!HasPosition(InpMagicNumberRSIFollow))
{
trade.SetExpertMagicNumber(InpMagicNumberRSIFollow);
trade.Sell(InpLotSize, _Symbol, 0, 0, 0, "RSI Follow");
}
rsiOverbought = false;
}
else if(rsiOversold && rsi[1] > rsi[0] && rsi[1] > InpRSIExitLevel)
{
// Buy signal
if(!HasPosition(InpMagicNumberRSIFollow))
{
trade.SetExpertMagicNumber(InpMagicNumberRSIFollow);
trade.Buy(InpLotSize, _Symbol, 0, 0, 0, "RSI Follow");
}
rsiOversold = false;
}
}
//+------------------------------------------------------------------+
//| Check if RSI Reverse is in cooldown |
//+------------------------------------------------------------------+
bool IsRSIReverseInCooldown()
{
if(InpRSIReverseCooldownBars <= 0)
return false;
if(!rsiReverseInCooldown)
return false;
datetime time[];
if(CopyTime(_Symbol, InpTimeframe, 0, 1, time) > 0)
{
datetime currentBarTime = time[0];
datetime cooldownEndTime = rsiReverseLastCloseTime + InpRSIReverseCooldownBars * PeriodSeconds(InpTimeframe);
if(currentBarTime >= cooldownEndTime)
{
rsiReverseInCooldown = false;
return false;
}
}
return true;
}
//+------------------------------------------------------------------+
//| Check for RSI Reverse Strategy signals |
//+------------------------------------------------------------------+
void CheckRSIReverseStrategy()
{
// Check if within trading hours
if(!IsWithinTradingHours(InpRSIReverseStartHour, InpRSIReverseEndHour))
{
if(InpRSIReverseCloseOutsideHours)
{
if(HasPosition(InpMagicNumberRSIReverse))
{
ClosePosition(InpMagicNumberRSIReverse);
}
}
return;
}
// Check strategy lock
if(InpEnableStrategyLock && HasProfitablePosition(InpMagicNumberRSIReverse))
return;
// Check cooldown
if(IsRSIReverseInCooldown())
return;
double rsi[];
ArraySetAsSeries(rsi, true);
CopyBuffer(rsiReverseHandle, 0, 0, 3, rsi);
if(ArraySize(rsi) < 3) return;
// Check for overbought/oversold conditions
if(rsi[1] > InpRSIReverseOverbought)
rsiReverseOverbought = true;
else if(rsi[1] < InpRSIReverseOversold)
rsiReverseOversold = true;
// Check for entry signals
if(rsiReverseOverbought && rsi[1] < InpRSIReverseCrossLevel)
{
// Sell signal
if(!HasPosition(InpMagicNumberRSIReverse))
{
trade.SetExpertMagicNumber(InpMagicNumberRSIReverse);
trade.Sell(InpLotSize, _Symbol, 0, 0, 0, "RSI Reverse");
}
rsiReverseOverbought = false;
}
else if(rsiReverseOversold && rsi[1] > InpRSIReverseCrossLevel)
{
// Buy signal
if(!HasPosition(InpMagicNumberRSIReverse))
{
trade.SetExpertMagicNumber(InpMagicNumberRSIReverse);
trade.Buy(InpLotSize, _Symbol, 0, 0, 0, "RSI Reverse");
}
rsiReverseOversold = false;
}
}
//+------------------------------------------------------------------+
//| Check for EMA Cross Strategy signals |
//+------------------------------------------------------------------+
void CheckEMACrossStrategy()
{
// Check if within trading hours
if(!IsWithinTradingHours(InpEMACrossStartHour, InpEMACrossEndHour))
{
if(InpEMACrossCloseOutsideHours)
{
if(HasPosition(InpMagicNumberEMACross))
{
ClosePosition(InpMagicNumberEMACross);
}
}
return;
}
// Check strategy lock
if(InpEnableStrategyLock && HasProfitablePosition(InpMagicNumberEMACross))
return;
double ema[], close[];
ArraySetAsSeries(ema, true);
ArraySetAsSeries(close, true);
CopyBuffer(emaHandle, 0, 0, InpEMADistancePeriod + 2, ema);
CopyClose(_Symbol, InpTimeframe, 0, InpEMADistancePeriod + 2, close);
if(ArraySize(ema) < InpEMADistancePeriod + 2 || ArraySize(close) < InpEMADistancePeriod + 2) return;
// Check for cross signals
if(ema[1] < close[1] && ema[0] > close[0])
{
// Buy cross signal
emaCrossBuySignal = true;
emaCrossSellSignal = false;
emaCrossSignalBar = 0;
}
else if(ema[1] > close[1] && ema[0] < close[0])
{
// Sell cross signal
emaCrossSellSignal = true;
emaCrossBuySignal = false;
emaCrossSignalBar = 0;
}
// Check for distance entry conditions
if(InpUseEMADistanceEntry)
{
if(emaCrossBuySignal)
{
// Check if price has moved above EMA by the required distance for the required period
bool distanceConditionMet = true;
for(int i = 0; i < InpEMADistancePeriod; i++)
{
double distance = (close[i] - ema[i]) / _Point;
if(distance < InpEMADistancePips)
{
distanceConditionMet = false;
break;
}
}
if(distanceConditionMet && !HasPosition(InpMagicNumberEMACross))
{
trade.SetExpertMagicNumber(InpMagicNumberEMACross);
trade.Buy(InpLotSize, _Symbol, 0, 0, 0, "EMA Cross Distance");
emaCrossBuySignal = false;
}
}
else if(emaCrossSellSignal)
{
// Check if price has moved below EMA by the required distance for the required period
bool distanceConditionMet = true;
for(int i = 0; i < InpEMADistancePeriod; i++)
{
double distance = (ema[i] - close[i]) / _Point;
if(distance < InpEMADistancePips)
{
distanceConditionMet = false;
break;
}
}
if(distanceConditionMet && !HasPosition(InpMagicNumberEMACross))
{
trade.SetExpertMagicNumber(InpMagicNumberEMACross);
trade.Sell(InpLotSize, _Symbol, 0, 0, 0, "EMA Cross Distance");
emaCrossSellSignal = false;
}
}
}
else
{
// Original cross entry logic
if(ema[1] < close[1] && ema[0] > close[0])
{
// Buy signal
if(!HasPosition(InpMagicNumberEMACross))
{
trade.SetExpertMagicNumber(InpMagicNumberEMACross);
trade.Buy(InpLotSize, _Symbol, 0, 0, 0, "EMA Cross");
}
}
else if(ema[1] > close[1] && ema[0] < close[0])
{
// Sell signal
if(!HasPosition(InpMagicNumberEMACross))
{
trade.SetExpertMagicNumber(InpMagicNumberEMACross);
trade.Sell(InpLotSize, _Symbol, 0, 0, 0, "EMA Cross");
}
}
}
// Increment signal bar counter
if(emaCrossBuySignal || emaCrossSellSignal)
{
emaCrossSignalBar++;
// Reset signals if they're too old (optional, can be removed if not needed)
if(emaCrossSignalBar > InpEMADistancePeriod * 2)
{
emaCrossBuySignal = false;
emaCrossSellSignal = false;
}
}
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// Only process on new bar
if(!IsNewBar())
return;
// Check for new signals
if(InpEnableRSIFollow)
CheckRSIFollowStrategy();
if(InpEnableRSIReverse)
CheckRSIReverseStrategy();
if(InpEnableEMACross)
CheckEMACrossStrategy();
// Check for exit conditions
CheckExitConditions();
}
//+------------------------------------------------------------------+
//| Check exit conditions for all strategies |
//+------------------------------------------------------------------+
void CheckExitConditions()
{
double rsi[], rsiReverse[], ema[], close[];
ArraySetAsSeries(rsi, true);
ArraySetAsSeries(rsiReverse, true);
ArraySetAsSeries(ema, true);
ArraySetAsSeries(close, true);
if(InpEnableRSIFollow)
{
CopyBuffer(rsiHandle, 0, 0, 1, rsi);
// Check RSI Follow exit conditions
if(HasPosition(InpMagicNumberRSIFollow))
{
if((positionInfo.PositionType() == POSITION_TYPE_BUY && rsi[0] < InpRSIExitLevel) ||
(positionInfo.PositionType() == POSITION_TYPE_SELL && rsi[0] > InpRSIExitLevel))
{
ClosePosition(InpMagicNumberRSIFollow);
}
}
}
if(InpEnableRSIReverse)
{
CopyBuffer(rsiReverseHandle, 0, 0, 1, rsiReverse);
// Check RSI Reverse exit conditions
if(HasPosition(InpMagicNumberRSIReverse))
{
if((positionInfo.PositionType() == POSITION_TYPE_BUY && rsiReverse[0] < InpRSIReverseExitLevel) ||
(positionInfo.PositionType() == POSITION_TYPE_SELL && rsiReverse[0] > InpRSIReverseExitLevel))
{
ClosePosition(InpMagicNumberRSIReverse);
}
}
}
if(InpEnableEMACross)
{
CopyBuffer(emaHandle, 0, 0, 2, ema);
CopyClose(_Symbol, InpTimeframe, 0, 2, close);
// Check EMA Cross exit conditions
if(HasPosition(InpMagicNumberEMACross))
{
if((positionInfo.PositionType() == POSITION_TYPE_BUY && ema[0] > close[0]) ||
(positionInfo.PositionType() == POSITION_TYPE_SELL && ema[0] < close[0]))
{
ClosePosition(InpMagicNumberEMACross);
}
}
}
}
//+------------------------------------------------------------------+
//| Close position by magic number |
//+------------------------------------------------------------------+
void ClosePosition(int magic)
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(positionInfo.SelectByIndex(i))
{
if(positionInfo.Magic() == magic)
{
// Check if this is RSI Reverse position and update cooldown
if(magic == InpMagicNumberRSIReverse)
{
datetime time[];
if(CopyTime(_Symbol, InpTimeframe, 0, 1, time) > 0)
{
rsiReverseLastCloseTime = time[0];
// Only enter cooldown if it's a loss or if cooldown on loss is disabled
if(!InpRSIReverseCooldownOnLoss || positionInfo.Profit() < 0)
{
rsiReverseInCooldown = true;
}
}
}
trade.PositionClose(positionInfo.Ticket());
break;
}
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 242 KiB