This script is designed to identify potential breakout trading opportunities in the market, using volatility and momentum. It does this by combining two different types of indicators: Bollinger Bands and Keltner Channels, along with a Momentum indicator. Think of it as a weather forecaster trying to predict a storm based on multiple readings.
Here's how it works:
-
Measuring Volatility Squeeze: The script first compares Bollinger Bands and Keltner Channels. Bollinger Bands measure how spread out the price is around its average, while Keltner Channels measure the average trading range. When Bollinger Bands are inside the Keltner Channels, it signals a period of low volatility, like a tightly coiled spring ready to release. This is considered a "squeeze". When the Bollinger Bands break out of the Keltner Channels, it suggests that volatility is increasing and a potential price move is coming.
-
Visual Representation: The script shows these volatility conditions using a histogram (a bar chart).
- Green bars indicate that the Bollinger Bands are outside the Keltner Channels, suggesting a potential breakout is happening, or a period of high volatility. Taller green bars mean a stronger potential move.
- Red bars indicate that the Bollinger Bands are inside the Keltner Channels, representing a period of low volatility or consolidation. Taller red bars mean the price action is becoming more tightly compressed.
-
Momentum Check: To refine the potential breakout signal, the script uses a Momentum indicator. Momentum measures the speed or rate of price change. This helps to determine the direction of the potential breakout.
- If the Momentum indicator is above zero when the Bollinger Bands break outside the Keltner Channels, the script interprets this as a possible upward breakout.
- If the Momentum indicator is below zero during the breakout, it suggests a potential downward breakout.
-
Alerts and On-Screen Info: The script provides alerts in two ways:
- Visual Alerts: The script will create colored arrows on the chart in real time.
- Audible Alerts: When a potential breakout is identified (based on the combined signals of volatility and momentum), the script can trigger an audio alert to notify the trader. The script is designed to only alert once per bar.
- On-Screen Information: The script will show other indicators like Average True Range (ATR), Average Directional Index (ADX), Relative Strength Index (RSI), Moving Average Convergence Divergence (MACD), and Stochastic Oscillator.
-
Customization: The user can adjust several parameters, such as the periods used in calculating the Bollinger Bands, Keltner Channels, and Momentum indicator, to fine-tune the script's sensitivity.
In essence, this script is like a multi-tool for traders, combining different indicators to identify periods of low volatility that may lead to significant price moves, and then using momentum to anticipate the direction of those moves. It's a way to scan the market for situations where prices are "squeezed" and ready to "pop."
//+------------------------------------------------------------------+
//| Des_Squeeze_Play.mq4 |
//| DesO'Regan |
//| mailto: oregan_des@hotmail.com |
//+------------------------------------------------------------------+
// ===========================================================================================================
// This indicator is based on a strategy mentioned in John Carter's book, Mastering the Trade. The basic idea
// behind the strategy is that markets tend to move from periods of low volatility to high volatility and
// visa versa. The strategy aims to capture moves from low to high volatility. For gauging this he uses two
// common indicators - Bollinger Bands and Keltner Channels (ok, not so common!). He also uses the Momentum
// indicator to provide a trade bias as soon as the Bollinger Bands come back outside the Keltner Channels.
//
// The Squeeze_Break indicator combines this into a signal indicator and has the following components:
// 1. A positive green histogram means that the Bollinger Bands are outside the Keltner Channels
// and the market is lightly to be trending or volatile. The stronger the histogram the stronger
// the directional price move.
// 2. A negative red histogram means that the Bollinger Bands are inside the Keltner Channels
// and the market is lightly to be consolidating. The stronger the red histogram the tighter
// price action is becoming.
// 3. Incorporated into the indicator is a Momentum indicator. According to the strategy J. Carter
// goes long when the Bollinger Bands break outside the Keltner Bands and the Momentum indicator
// is above the zero line. He goes short when the Momentum indicator is below the zero line on the
// break.
// 4. I've also added other indicator info in the top left hand corner to give a broader idea
// of current market conditions.
// 5. The indicator provides audio alerts when a potential breakout is occurring.
//
// This indicator tends to be better with the larger timeframes. Personally I don't trade on an alert
// signal alone. It's just a handy tool for warning me of potential breakout trades.
// ===========================================================================================================
#property copyright "DesORegan"
#property link "mailto: oregan_des@hotmail.com"
// ====================
// indicator properties
// ====================
#property indicator_separate_window
#property indicator_buffers 3
#property indicator_color1 ForestGreen
#property indicator_color2 Red
#property indicator_color3 Blue
// ===================
// User Inputs
// ===================
extern int Boll_Period=20;
extern double Boll_Dev=2.0;
extern int Keltner_Period=20;
extern double Keltner_Mul=1.5;
extern int Momentum_Period=12;
extern int Back_Bars=1000;
extern bool Alert_On=true;
extern bool On_Screen_Info=true;
// =========================
// Buffer Array Declarations
// =========================
double Pos_Diff[]; // Pos Histogram
double Neg_Diff[]; // Neg Histogram
double Momentum[]; // Momentum Indicator
// ===========================
// Internal Array Declarations
// ===========================
double Squeeze[]; // Used to track which "i" (index value) is above
// and below zero line. 0 followed by 1 triggers alert
// =========================
// Internal Global Variables
// =========================
datetime Last_Alert_Time=0; // Used to prevent continuous alerts on current bar
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int init()
{
IndicatorDigits(4); // indicator value precision
//======================
// Indicator Setup
//======================
SetIndexStyle(0,DRAW_HISTOGRAM,EMPTY,3);
SetIndexBuffer(0,Pos_Diff);
SetIndexStyle(1,DRAW_HISTOGRAM,EMPTY,3);
SetIndexBuffer(1,Neg_Diff);
SetIndexStyle(2,DRAW_LINE,STYLE_DOT);
SetIndexBuffer(2,Momentum);
// ===================
// Indicator Labels
// ===================
IndicatorShortName("Squeeze_Break (Boll:"+Boll_Period+","+DoubleToStr(Boll_Dev,1)+";Kelt:"+Keltner_Period+","+DoubleToStr(Keltner_Mul,1)+";Mom:"+Momentum_Period+")");
// ====================
// Array Initialization
// ====================
ArrayResize(Squeeze,Back_Bars); // Stores whether histogram is above/below zero line
ArrayInitialize(Squeeze,0); // initialises array with 0's
return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
ObjectsDeleteAll();
Comment(" ","\n",
" ","\n",
" ","\n",
" ","\n",
" ");
return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int start()
{
//=======================
// Indicator Optimization
//=======================
int Counted_Bars=IndicatorCounted();
if(Counted_Bars < 0) return(-1);
if(Counted_Bars>0) Counted_Bars--;
int limit=Bars-Counted_Bars;
if(Counted_Bars==0) limit-=1+MathMax(Momentum_Period,Keltner_Period);
ArrayResize(Squeeze,ArraySize(Momentum));
//=======================
// On-Screen Information
//=======================
if(On_Screen_Info==true)
{
double ATR=iATR(Symbol(),PERIOD_D1,14,0);
double Todays_Range=iHigh(Symbol(),PERIOD_D1,0)-iLow(Symbol(),PERIOD_D1,0);
double ADX = iADX(Symbol(),0,12,PRICE_CLOSE,MODE_MAIN,0);
double RSI = iRSI(Symbol(),0,12,PRICE_CLOSE,0);
double MACD_Main=iMACD(Symbol(),0,12,26,9,PRICE_CLOSE,MODE_MAIN,0);
double MACD_Signal=iMACD(Symbol(),0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,0);
double Sto_Main=iStochastic(Symbol(),0,10,3,3,MODE_SMA,1,MODE_MAIN,0);
double Sto_Signal=iStochastic(Symbol(),0,10,3,3,MODE_SMA,1,MODE_SIGNAL,0);
Comment("-----------------------------------------------------------------",
"\nDaily ATR(14): ",ATR," Todays Range: ",Todays_Range,
"\nADX(12): ",NormalizeDouble(ADX,2)," RSI(12): ",NormalizeDouble(RSI,2),
"\nMACD(12,26,9): ",MACD_Main,", ",MACD_Signal,
"\nStochastic(10,3,3): ",NormalizeDouble(Sto_Main,2),", ",NormalizeDouble(Sto_Signal,2),
"\n-----------------------------------------------------------------");
}
//======================
// Main Indicator Loop
//======================
for(int i=limit; i>=0; i--) //main indicator FOR loop
{
// ======================
// Indicator Calculations
// ======================
double MA_Hi = iMA(Symbol(),0,Keltner_Period,0,MODE_SMA,PRICE_HIGH,i);
double MA_Lo = iMA(Symbol(),0,Keltner_Period,0,MODE_SMA,PRICE_LOW,i);
double Kelt_Mid_Band=iMA(Symbol(),0,Keltner_Period,0,MODE_SMA,PRICE_TYPICAL,i);
double Kelt_Upper_Band = Kelt_Mid_Band + ((MA_Hi - MA_Lo)*Keltner_Mul);
double Kelt_Lower_Band = Kelt_Mid_Band - ((MA_Hi - MA_Lo)*Keltner_Mul);
double Boll_Upper_Band = iBands(Symbol(),0, Boll_Period,Boll_Dev,0,PRICE_CLOSE, MODE_UPPER,i);
double Boll_Lower_Band = iBands(Symbol(),0, Boll_Period,Boll_Dev,0,PRICE_CLOSE, MODE_LOWER,i);
// ======================
// Buffer Calculations
// ======================
Momentum[i]=(Close[i]-Close[i+Momentum_Period]);
if(Boll_Upper_Band>=Kelt_Upper_Band || Boll_Lower_Band<=Kelt_Lower_Band)
{
Pos_Diff[i]=(MathAbs(Boll_Upper_Band-Kelt_Upper_Band)+MathAbs(Boll_Lower_Band-Kelt_Lower_Band));
Squeeze[i] = 1;
}
else
{
Pos_Diff[i]=0;
}
if(Boll_Upper_Band<Kelt_Upper_Band && Boll_Lower_Band>Kelt_Lower_Band)
{
Neg_Diff[i]= -(MathAbs(Boll_Upper_Band-Kelt_Upper_Band)+MathAbs(Boll_Lower_Band-Kelt_Lower_Band));
Squeeze[i] = 0;
}
else
{
Neg_Diff[i]=0;
}
// ======================
// Trigger Check
// ======================
if(Squeeze[i]==1 && Squeeze[i+1]==0 && Momentum[i]>0 && i==0) // a cross above zero line and Mom > 0
{
if(Last_Alert_Time!=Time[0])
{
if(Alert_On==true) Alert("Alert: Possible Breakout - "+Symbol()+" - "+TimeToStr(TimeLocal()));
Last_Alert_Time=Time[0];
ObjectCreate("Breakout"+Time[0],OBJ_ARROW,0,Time[0],Ask);
ObjectSet("Breakout"+Time[0],OBJPROP_ARROWCODE,1);
ObjectSet("Breakout"+Time[0],OBJPROP_COLOR,Blue);
ObjectSet("Breakout"+Time[0],OBJPROP_WIDTH,2);
}
}
if(Squeeze[i]==1 && Squeeze[i+1]==0 && Momentum[i]<0 && i==0) // a cross above zero line and Mom < 0
{
if(Last_Alert_Time!=Time[0])
{
if(Alert_On==true) Alert("Alert: Possible Breakout - "+Symbol()+" - "+TimeToStr(TimeLocal()));
Last_Alert_Time=Time[0];
ObjectCreate("Breakout"+Time[0],OBJ_ARROW,0,Time[0],Bid);
ObjectSet("Breakout"+Time[0],OBJPROP_ARROWCODE,1);
ObjectSet("Breakout"+Time[0],OBJPROP_COLOR,Red);
ObjectSet("Breakout"+Time[0],OBJPROP_WIDTH,2);
}
}
} // end of main indicator FOR loop
return(0);
}
//+------------------------------------------------------------------+
Comments