Overview of the Batfink Daily Range Indicator
This script is designed to help traders identify specific price "breakout" opportunities by analyzing historical price movements during defined time segments of the trading day. It automates the process of identifying volatility zones and highlighting the moments when the price moves beyond those established boundaries.
Core Logic and Functionality
1. Time Zone Management The indicator is built to handle global markets by allowing users to adjust for different time zones. It calculates the difference between the broker's local time and your desired home time (such as GMT). This ensures that the "trading day" logic remains consistent regardless of which server you are connected to.
2. Dynamic Zone Identification Instead of using a static price range, the script divides the trading day into specific chronological periods. It scans historical data to determine the price action during these segments:
- It identifies the highs and lows of early market sessions.
- As these initial time blocks conclude, the script captures the price extremes reached during that time.
3. The "Entry Zone" Calculation Once a primary period is completed, the indicator projects a dynamic range onto your chart. It takes the closing price of the completed period and adds/subtracts a user-defined number of pips (the "PipsForEntry" setting) to create an upper and lower boundary line. This creates a "no-trade" or "waiting" zone, where the indicator looks for the price to push significantly past the previous session's volatility.
4. Breakout Signal Detection The script continuously monitors the current market price against these calculated boundaries. It looks for specific "breakout" behaviors:
- Buy Signals: Triggered when the price moves upward and crosses through the upper boundary line.
- Sell Signals: Triggered when the price moves downward and crosses through the lower boundary line.
The indicator validates these signals by checking if the price action (the relationship between the candle's opening, closing, high, and low points) actually intersects with the calculated zone.
5. Visual Feedback and Alerts To make the data actionable for the user, the script provides three types of feedback:
- Visual Lines: It draws the upper and lower boundary lines directly on your chart so you can see the current "active" range.
- On-Chart Arrows: When a breakout occurs, an arrow is placed on the chart to mark the exact moment the price breached the zone.
- Real-Time Alerts: If enabled, the script will trigger a pop-up notification on your trading platform the moment a price breaks out of the range, allowing you to react instantly without constantly watching the screen.
Summary for the User
In essence, this tool helps you filter out market "noise." By defining what the "normal" range was during the morning or opening hours, it highlights the specific moments when the price makes a significant move in one direction, potentially signaling a new trend or a high-volatility breakout.
//+------------------------------------------------------------------+
//| Batfink Daily Range.MT4 |
//| |
//+------------------------------------------------------------------+
/* Introduction:
Draw Line at 00:00GMT + and - 70
TimeZONE Information - Indicator can be used for different Time Zones.
For Batfink settings set to -5 for MetaQuotes demo Server
This will place home line at 00:00GMT Time
*/
#property indicator_chart_window
#property indicator_buffers 3
#property indicator_color1 White
#property indicator_color2 White
#property indicator_color3 Orange
extern bool DoEntryAlerts= false;
extern int LocalTimeZone= 2;
extern int DestTimeZone= 0;
extern int PipsForEntry= 70;
double Zone1Upper[];
double Zone1Lower[];
double EntrySignalsBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int init()
{
SetIndexStyle(0,DRAW_LINE);
SetIndexBuffer(0,Zone1Upper);
SetIndexEmptyValue(0, 0.0);
SetIndexStyle(1,DRAW_LINE);
SetIndexBuffer(1,Zone1Lower);
SetIndexEmptyValue(1, 0.0);
SetIndexStyle(2,DRAW_ARROW);
SetIndexArrow(2, 141);
SetIndexBuffer(2, EntrySignalsBuffer);
SetIndexEmptyValue(2, 0.0);
SetIndexLabel(2, "Zone Breakout Signal");
return(0);
}
int deinit()
{
return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int start()
{
int counted_bars= IndicatorCounted(),
lastbar, result;
if (Bars<=100)
return(0);
if (counted_bars>0)
counted_bars--;
lastbar= Bars - counted_bars;
BreakoutRanges(0, lastbar, LocalTimeZone, DestTimeZone);
//
// check alerts
//
static datetime lastalerttime;
static double lastalertprice;
if (DoEntryAlerts && lastalerttime!=Time[0] && EntrySignalsBuffer[0]!=0 && EntrySignalsBuffer[0]!=lastalertprice) {
Alert("ZoneBreakout signals entry!");
lastalerttime= Time[0];
lastalertprice= EntrySignalsBuffer[0];
}
else {
lastalerttime= 0;
lastalertprice= 0.0;
}
return(0);
}
//+------------------------------------------------------------------+
//| Compute index of first/last bar of yesterday and today |
//+------------------------------------------------------------------+
int BreakoutRanges(int offset, int lastbar, int tzlocal, int tzdest)
{
int i, j, k,
tzdiff= tzlocal - tzdest,
tzdiffsec= tzdiff*3600,
tidxstart[2]= { 0, 0},
tidxend[2]= { 0, 0 };
double topen[2]= { 0.0, 0.0 },
tclose[2]= { 99999.9, 99999.9 };
string tfrom[3]= { "07:00", "08:00" , /*rest of day: */ "12:00"},
tto[3]= { "08:00", "12:00", /*rest of day: */ "24:00" },
tday;
bool inperiod= -1;
datetime timet;
//
// search back for the beginning of the day
//
tday= TimeToStr(Time[lastbar]-tzdiffsec, TIME_DATE);
for ( ; lastbar<Bars; lastbar++) {
if (TimeToStr(Time[lastbar] - tzdiffsec, TIME_DATE)!=tday) {
lastbar--;
break;
}
}
//
// find the high/low for the two periods and carry them forward through the day
//
tday= "XXX";
for (i= lastbar; i>=offset; i--) {
timet= Time[i] - tzdiffsec; // time of this bar
string timestr= TimeToStr(timet, TIME_MINUTES), // current time HH:MM
thisday= TimeToStr(timet, TIME_DATE); // current date
EntrySignalsBuffer[i]= 0;
//
// for all three periods (first period, second period, rest of day)
//
for (j= 0; j<3; j++) {
if (tfrom[j]<=timestr && timestr<tto[j]) { // Bar[i] in this period
if (inperiod!=j) { // entered new period, so last one is completed
if (j>0) { // now draw high/low back over the recently completed period
for (k= tidxstart[j-1]; k>=tidxend[j-1]; k--) {
if (j-1==0) {
Zone1Upper[k]= tclose[j-1];
Zone1Lower[k]= tclose[j-1];
}
}
inperiod= j; // remember current period
}
// for the current period find idxstart, idxend and compute high/low
if (tidxstart[j]==0) {
tidxstart[j]= i;
tday= thisday;
}
tidxend[j]= i;
topen[j]= MathMax(topen[j], Open[i]);
tclose[j]= MathMin(tclose[j], Close[i]);
}
}
//------------------------------------------------------------------------
// carry forward the periods for which we have definite high/lows
//
if (inperiod>=1 && tday==thisday) { // first time period completed
Zone1Upper[i]= tclose[0] + PipsForEntry*Point;
Zone1Lower[i]= tclose[0] - PipsForEntry*Point;
}
CheckSignal(i, Zone1Upper[i], OP_BUY, EntrySignalsBuffer);
CheckSignal(i, Zone1Lower[i], OP_SELL, EntrySignalsBuffer);
}
{ // none yet to carry forward (zero to clear old values, e.g. from switching timeframe)
Zone1Upper[i]= 0;
Zone1Lower[i]= 0;
}
//
// at the beginning of a new day reset everything
//
if (tday!="XXX" && tday!=thisday) {
Print("#", i, "new day ", thisday, "/", tday);
tday= "XXX";
inperiod= -1;
for (j= 0; j<2; j++) {
tidxstart[j]= 0;
tidxend[j]= 0;
topen[j]= 0;
tclose[j]= 99999;
}
}
}
return (0);
}
//+------------------------------------------------------------------+
//| Check price break |
//+------------------------------------------------------------------+
bool CheckSignal(int shift, double price, int type, double &signalbuffer[])
{
bool signal= false;
if (type==OP_BUY && ((Open[shift]<price && High[shift]>price) || (Close[shift+1]<price && Open[shift]>price)) ) {
signalbuffer[shift]= price;
signal= true;
}
if (type==OP_SELL && (Open[shift]>price && Low[shift]<price) || (Close[shift+1]>price && Open[shift]<price)) {
signalbuffer[shift]= price;
signal= true;
}
return (signal);
}
Comments