258 lines
7.5 KiB
Plaintext
258 lines
7.5 KiB
Plaintext
/*
|
|
============================================================
|
|
Demo File: Range_Breakout_EA - Signal Logic Showcase
|
|
Category: Breakout
|
|
Platform: MetaTrader 4 (MQL4)
|
|
Version: 1.0
|
|
Author: Giacomo Cipolat Bares
|
|
Portfolio: MQL4 Expert Advisors Portfolio
|
|
============================================================
|
|
|
|
Description:
|
|
This is a simplified public demo derived from the full
|
|
Range Breakout EA.
|
|
|
|
Included in this demo:
|
|
- range high/low detection
|
|
- breakout trigger calculation
|
|
- breakout buffer logic
|
|
- one-breakout-per-range logic
|
|
- breakout cooldown logic
|
|
- basic on-chart signal output
|
|
|
|
Excluded from this demo:
|
|
- order execution
|
|
- risk management engine
|
|
- break-even / trailing stop
|
|
- retry logic
|
|
- broker protection handling
|
|
- full production trade framework
|
|
- chart visualization layer
|
|
============================================================
|
|
*/
|
|
|
|
#property strict
|
|
#property version "1.00"
|
|
|
|
//========================= INPUTS ==================================
|
|
input string __01_BreakoutSettings = "01 ======== Breakout Settings ========";
|
|
input int BreakoutBars = 20;
|
|
input double BreakoutBufferPips = 0.5;
|
|
input bool UseCloseBreakout = false;
|
|
input bool OneBreakoutPerRange = true;
|
|
input bool ResetRangeAfterTrade = true;
|
|
input bool UseBreakoutCooldown = true;
|
|
input int BreakoutCooldownBars = 5;
|
|
|
|
//======================= BREAKOUT GLOBALS ==========================
|
|
double g_lastRangeHigh = 0.0;
|
|
double g_lastRangeLow = 0.0;
|
|
bool g_rangeAlreadyTraded = false;
|
|
int g_lastTradeBarIndex = -1;
|
|
|
|
//======================= GENERAL GLOBALS ===========================
|
|
double g_point;
|
|
double g_pip;
|
|
int g_digits;
|
|
datetime g_lastBarTime = 0;
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert initialization |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
g_point = Point;
|
|
g_digits = Digits;
|
|
|
|
if(g_digits == 5 || g_digits == 3)
|
|
g_pip = g_point * 10.0;
|
|
else
|
|
g_pip = g_point;
|
|
|
|
Print("Range Breakout demo initialized");
|
|
return(INIT_SUCCEEDED);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Detects a new bar |
|
|
//+------------------------------------------------------------------+
|
|
bool IsNewBar()
|
|
{
|
|
datetime currentBarTime = iTime(NULL, 0, 0);
|
|
|
|
if(currentBarTime != g_lastBarTime)
|
|
{
|
|
g_lastBarTime = currentBarTime;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Range high from previous N bars |
|
|
//+------------------------------------------------------------------+
|
|
double GetBreakoutHigh()
|
|
{
|
|
int highestIndex = iHighest(NULL, 0, MODE_HIGH, BreakoutBars, 1);
|
|
return High[highestIndex];
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Range low from previous N bars |
|
|
//+------------------------------------------------------------------+
|
|
double GetBreakoutLow()
|
|
{
|
|
int lowestIndex = iLowest(NULL, 0, MODE_LOW, BreakoutBars, 1);
|
|
return Low[lowestIndex];
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Bullish breakout condition |
|
|
//+------------------------------------------------------------------+
|
|
bool IsBullishBreakout()
|
|
{
|
|
double breakoutHigh = GetBreakoutHigh();
|
|
double triggerPrice = breakoutHigh + BreakoutBufferPips * g_pip;
|
|
|
|
if(UseCloseBreakout)
|
|
return (Close[1] > triggerPrice);
|
|
|
|
return (Ask > triggerPrice);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Bearish breakout condition |
|
|
//+------------------------------------------------------------------+
|
|
bool IsBearishBreakout()
|
|
{
|
|
double breakoutLow = GetBreakoutLow();
|
|
double triggerPrice = breakoutLow - BreakoutBufferPips * g_pip;
|
|
|
|
if(UseCloseBreakout)
|
|
return (Close[1] < triggerPrice);
|
|
|
|
return (Bid < triggerPrice);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Checks if current range is same as previous tracked range |
|
|
//+------------------------------------------------------------------+
|
|
bool IsSameRange(double rangeHigh, double rangeLow)
|
|
{
|
|
if(MathAbs(rangeHigh - g_lastRangeHigh) < (g_point * 0.5) &&
|
|
MathAbs(rangeLow - g_lastRangeLow) < (g_point * 0.5))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Updates tracked breakout range |
|
|
//+------------------------------------------------------------------+
|
|
void UpdateRangeState()
|
|
{
|
|
double currentRangeHigh = GetBreakoutHigh();
|
|
double currentRangeLow = GetBreakoutLow();
|
|
|
|
if(!IsSameRange(currentRangeHigh, currentRangeLow))
|
|
{
|
|
g_lastRangeHigh = currentRangeHigh;
|
|
g_lastRangeLow = currentRangeLow;
|
|
|
|
if(ResetRangeAfterTrade)
|
|
g_rangeAlreadyTraded = false;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| One breakout per range filter |
|
|
//+------------------------------------------------------------------+
|
|
bool CanTradeCurrentRange()
|
|
{
|
|
if(!OneBreakoutPerRange)
|
|
return true;
|
|
|
|
if(g_rangeAlreadyTraded)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Breakout cooldown filter |
|
|
//+------------------------------------------------------------------+
|
|
bool BreakoutCooldownPassed()
|
|
{
|
|
if(!UseBreakoutCooldown)
|
|
return true;
|
|
|
|
if(g_lastTradeBarIndex < 0)
|
|
return true;
|
|
|
|
int barsPassed = Bars - g_lastTradeBarIndex;
|
|
|
|
if(barsPassed >= BreakoutCooldownBars)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Demo buy signal wrapper |
|
|
//+------------------------------------------------------------------+
|
|
bool BuySignal()
|
|
{
|
|
if(!CanTradeCurrentRange())
|
|
return false;
|
|
|
|
if(!BreakoutCooldownPassed())
|
|
return false;
|
|
|
|
return IsBullishBreakout();
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Demo sell signal wrapper |
|
|
//+------------------------------------------------------------------+
|
|
bool SellSignal()
|
|
{
|
|
if(!CanTradeCurrentRange())
|
|
return false;
|
|
|
|
if(!BreakoutCooldownPassed())
|
|
return false;
|
|
|
|
return IsBearishBreakout();
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert tick |
|
|
//+------------------------------------------------------------------+
|
|
void OnTick()
|
|
{
|
|
if(!IsNewBar())
|
|
return;
|
|
|
|
UpdateRangeState();
|
|
|
|
if(BuySignal())
|
|
{
|
|
g_lastTradeBarIndex = Bars;
|
|
g_rangeAlreadyTraded = true;
|
|
Comment("Demo Signal: BUY breakout detected");
|
|
return;
|
|
}
|
|
|
|
if(SellSignal())
|
|
{
|
|
g_lastTradeBarIndex = Bars;
|
|
g_rangeAlreadyTraded = true;
|
|
Comment("Demo Signal: SELL breakout detected");
|
|
return;
|
|
}
|
|
|
|
Comment("Demo Signal: No valid breakout");
|
|
} |