Trendlines2
Download scriptOverview
This script is a specialized visual tool designed for traders to identify and automatically display key trendlines on their trading charts. It simplifies the process of technical analysis by scanning historical price data to find significant "peaks" (Resistance) and "troughs" (Support) across multiple timeframes. Instead of requiring you to manually draw lines, the script identifies these structural points and renders them automatically.
Core Logic and Functionality
1. Multi-Timeframe Awareness The script is designed to be context-aware. Depending on which timeframe you are currently viewing on your chart (e.g., a 15-minute chart vs. a Daily chart), the script adjusts its behavior. It provides a comprehensive view by calculating and displaying trendlines from various perspectives: Weekly (W1), Daily (D1), 4-Hour (H4), 1-Hour (H1), and 15-Minute (M15).
2. Dynamic Identification of Price Extremes The internal logic works by scanning the price history to find two specific types of price points:
- Higher Highs (Resistance): The script looks for "peaks" where the price reached a point higher than its immediate neighbors. These areas represent historical ceilings where the market struggled to move upward.
- Lower Lows (Support): Conversely, the script scans for "troughs" where the price reached a point lower than its surrounding values. These represent historical floors where the market found a base.
3. Automated Trendline Construction Once the script identifies the most significant recent peaks and troughs for each timeframe, it performs the following actions:
- Connection: It draws a line connecting these two identified points to create a trendline.
- Positioning: If you are viewing a smaller timeframe (like 15 minutes) but looking at higher timeframe data (like Daily), the script intelligently maps those historical coordinates onto your current view so they appear in the correct spatial location.
- Visual Differentiation: To help you distinguish between different timeframes at a glance, the script applies unique visual styles. For example, it varies the colors (blue for resistance, red for support), line thickness, and dash patterns based on whether the data is from a Weekly, Daily, Hourly, or smaller timeframe.
4. Visual Presentation
- Infinite Projection: The trendlines are set as "rays," meaning they project forward into the future, allowing you to see potential future zones of resistance or support.
- Background Integration: The lines are drawn in the background of your chart, ensuring that they provide valuable structural context without cluttering the actual price candles.
Summary of User Experience
For a trader, this means the chart will automatically populate with structured trendlines. By looking at the colors and styles, you can quickly see where major "walls" (Resistance) and "floors" (Support) sit across various time horizons simultaneously, helping to identify potential areas for entries, exits, or reversals without manual drawing.
//+------------------------------------------------------------------+
//| Trendlines2.mq4 |
//| Copyright © 2006, John Hitt |
//| jhitt@kanji.dyndns.org |
//| |
//| 2007-10-19 Fixed stack errors by MQL Service |
//| http://www.mqlservice.com |
//| |
//| $Id: //depot/mt4files/experts/indicators/Trendlines2.mq4#2 $ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2006, John Hitt"
#property link "jhitt@kanji.dyndns.org"
#property indicator_chart_window
extern color W1_R=RoyalBlue;
extern color W1_S=FireBrick;
extern color D1_R=RoyalBlue;
extern color D1_S=FireBrick;
extern color H4_R=RoyalBlue;
extern color H4_S=FireBrick;
extern color H1_R=RoyalBlue;
extern color H1_S=FireBrick;
extern color M15_R=RoyalBlue;
extern color M15_S=FireBrick;
#define RESISTANCE 1
#define SUPPORT 2
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int init()
{
//---- indicators
//----
return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
//----
ObjectDelete("W1_R");
ObjectDelete("W1_S");
ObjectDelete("D1_R");
ObjectDelete("D1_S");
ObjectDelete("H4_R");
ObjectDelete("H4_S");
ObjectDelete("H1_R");
ObjectDelete("H1_S");
ObjectDelete("M15_R");
ObjectDelete("M15_S");
ObjectDelete("M5_R");
ObjectDelete("M5_S");
//----
return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int start()
{
datetime currentbar = 0;
if (currentbar != Time[0])
{
switch (Period())
{
case PERIOD_W1:
Draw_W1_Trends();
break;
case PERIOD_D1:
Draw_D1_Trends();
break;
case PERIOD_H4:
Draw_H4_Trends();
break;
case PERIOD_H1:
case PERIOD_M30:
Draw_H4_Trends();
Draw_H1_Trends();
break;
case PERIOD_M15:
Draw_H1_Trends();
Draw_M15_Trends();
break;
default:
Draw_M15_Trends();
break;
}
}
return(0);
}
double rate_array[][6];
void Draw_M15_Trends()
{
int sbar=0;
int ebar=0;
int i;
ArrayCopyRates(rate_array, Symbol(), PERIOD_M15);
for (i=2; i < Bars; i++)
{
if (HigherHigh(i, 1, rate_array) == true)
{
//Print("HiherHigh: ", i);
if (ebar == 0)
ebar = i;
else if (sbar == 0 && rate_array[i][3] > rate_array[ebar][3]) // use 3 for high
sbar = i;
}
if (sbar !=0 && ebar !=0)
break;
}
DrawTrendline ("M15_R", ebar, sbar, PERIOD_M15, RESISTANCE, rate_array);
ebar = 0;
sbar = 0;
for (i=2; i < Bars; i++)
{
if (LowerLow(i, 1, rate_array) == true)
{
if (ebar == 0)
ebar = i;
else if (sbar == 0 && rate_array[i][2] < rate_array[ebar][2]) // use 2 for low
sbar = i;
}
if (sbar !=0 && ebar !=0)
break;
}
DrawTrendline ("M15_S", ebar, sbar, PERIOD_M15, SUPPORT, rate_array);
}
void Draw_H1_Trends()
{
int sbar=0;
int ebar=0;
int i;
ArrayCopyRates(rate_array, Symbol(), PERIOD_H1);
for (i=2; i < Bars; i++)
{
if (HigherHigh(i, 1, rate_array) == true)
{
//Print("HiherHigh: ", i);
if (ebar == 0)
ebar = i;
else if (sbar == 0 && rate_array[i][3] > rate_array[ebar][3]) // use 3 for high
sbar = i;
}
if (sbar !=0 && ebar !=0)
break;
}
DrawTrendline ("H1_R", ebar, sbar, PERIOD_H1, RESISTANCE, rate_array);
ebar = 0;
sbar = 0;
for (i=2; i < Bars; i++)
{
if (LowerLow(i, 1, rate_array) == true)
{
if (ebar == 0)
ebar = i;
else if (sbar == 0 && rate_array[i][2] < rate_array[ebar][2]) // use 2 for low
sbar = i;
}
if (sbar !=0 && ebar !=0)
break;
}
DrawTrendline ("H1_S", ebar, sbar, PERIOD_H1, SUPPORT, rate_array);
}
void Draw_H4_Trends()
{
int sbar=0;
int ebar=0;
int i;
ArrayCopyRates(rate_array, Symbol(), PERIOD_H4);
for (i=2; i < Bars; i++)
{
if (HigherHigh(i, 1, rate_array) == true)
{
//Print("HiherHigh: ", i);
if (ebar == 0)
ebar = i;
else if (sbar == 0 && rate_array[i][3] > rate_array[ebar][3]) // use 3 for high
sbar = i;
}
if (sbar !=0 && ebar !=0)
break;
}
DrawTrendline ("H4_R", ebar, sbar, PERIOD_H4, RESISTANCE, rate_array);
ebar = 0;
sbar = 0;
for (i=2; i < Bars; i++)
{
if (LowerLow(i, 1, rate_array) == true)
{
if (ebar == 0)
ebar = i;
else if (sbar == 0 && rate_array[i][2] < rate_array[ebar][2]) // use 2 for low
sbar = i;
}
if (sbar !=0 && ebar !=0)
break;
}
DrawTrendline ("H4_S", ebar, sbar, PERIOD_H4, SUPPORT, rate_array);
}
void Draw_D1_Trends()
{
int sbar=0;
int ebar=0;
int i;
ArrayCopyRates(rate_array, Symbol(), PERIOD_D1);
for (i=2; i < Bars; i++)
{
if (HigherHigh(i, 1, rate_array) == true)
{
//Print("HiherHigh: ", i);
if (ebar == 0)
ebar = i;
else if (sbar == 0 && rate_array[i][3] > rate_array[ebar][3]) // use 3 for high
sbar = i;
}
if (sbar !=0 && ebar !=0)
break;
}
DrawTrendline ("D1_R", ebar, sbar, PERIOD_D1, RESISTANCE, rate_array);
ebar = 0;
sbar = 0;
for (i=2; i < Bars; i++)
{
if (LowerLow(i, 1, rate_array) == true)
{
if (ebar == 0)
ebar = i;
else if (sbar == 0 && rate_array[i][2] < rate_array[ebar][2]) // use 2 for low
sbar = i;
}
if (sbar !=0 && ebar !=0)
break;
}
DrawTrendline ("D1_S", ebar, sbar, PERIOD_D1, SUPPORT, rate_array);
}
void Draw_W1_Trends()
{
int sbar=0;
int ebar=0;
int i;
ArrayCopyRates(rate_array, Symbol(), PERIOD_W1);
for (i=2; i < Bars; i++)
{
if (HigherHigh(i, 1, rate_array) == true)
{
//Print("HiherHigh: ", i);
if (ebar == 0)
ebar = i;
else if (sbar == 0 && rate_array[i][3] > rate_array[ebar][3]) // use 3 for high
sbar = i;
}
if (sbar !=0 && ebar !=0)
break;
}
DrawTrendline ("W1_R", ebar, sbar, PERIOD_W1, RESISTANCE, rate_array);
ebar = 0;
sbar = 0;
for (i=2; i < Bars; i++)
{
if (LowerLow(i, 1, rate_array) == true)
{
if (ebar == 0)
ebar = i;
else if (sbar == 0 && rate_array[i][2] < rate_array[ebar][2]) // use 2 for low
sbar = i;
}
if (sbar !=0 && ebar !=0)
break;
}
DrawTrendline ("W1_S", ebar, sbar, PERIOD_W1, SUPPORT, rate_array);
}
bool HigherHigh (int point, int shift, double array[][6])
{
if (shift == 0)
return (true);
if (array[point][3] >= array[point+shift][3] && array[point][3] >= array[point-shift][3])
{
if (array[point][3] == array[point+shift][3] || array[point][3] == array[point-shift][3])
{
if ((point - shift - 1) == 0)
return (false);
if (array[point][3] > array[point+shift+1][3] && array[point][3] > array[point-shift-1][3])
return (HigherHigh (point, shift-1, array));
else
return (false);
} else {
return (HigherHigh (point, shift-1, array));
}
}
else
return (false);
}
bool LowerLow (int point, int shift, double array[][6])
{
if (shift == 0)
return (true);
if (array[point][2] <= array[point+shift][2] && array[point][2] <= array[point-shift][2])
{
if (array[point][2] == array[point+shift][2] || array[point][2] == array[point-shift][2])
{
if ((point-shift-1) == 0)
return (false);
if (array[point][2] < array[point+shift+1][2] && array[point][2] < array[point-shift-1][2])
return(LowerLow (point, shift-1, array));
else
return (false);
} else {
return(LowerLow (point, shift-1, array));
}
}
else
return (false);
}
int GetRealPosition(int p1, double array[][6], int which, datetime value, double peak)
{
int i;
for (i=0; i < Bars; i++)
{
if (array[i][0] == value || array[i][0] < value)
{
if (which == RESISTANCE)
{
if (array[i][3] == peak) return (i);
if (array[i-1][3] == peak) return (i-1);
if (array[i-2][3] == peak) return (i-2);
if (array[i-3][3] == peak) return (i-3);
} else {
if (array[i][2] == peak) return (i);
if (array[i-1][2] == peak) return (i-1);
if (array[i-2][2] == peak) return (i-2);
if (array[i-3][2] == peak) return (i-3);
}
if (array[i][0] < value) return (i);
}
}
return (-1);
}
double array[][6];
int DrawTrendline (string name, int p1, int p2, int timeframe, int which, double r_array[][6])
{
color hue;
int thickness = 1;
int style = STYLE_DASH;
ArrayCopyRates(array, Symbol(), Period());
if (which == RESISTANCE)
{
hue = RoyalBlue;
if (Period() != timeframe)
{
p1 = GetRealPosition(p1, array, which, r_array[p1][0], r_array[p1][3]);
p2 = GetRealPosition(p2, array, which, r_array[p2][0], r_array[p2][3]);
}
}
else
{
hue = FireBrick;
if (Period() != timeframe)
{
p1 = GetRealPosition(p1, array, which, r_array[p1][0], r_array[p1][2]);
p2 = GetRealPosition(p2, array, which, r_array[p2][0], r_array[p2][2]);
}
}
switch(timeframe)
{
case PERIOD_W1:
thickness = 2;
style = STYLE_SOLID;
if (which == RESISTANCE)
hue = W1_R;
else
hue = W1_S;
break;
case PERIOD_D1:
thickness = 2;
style = STYLE_SOLID;
if (which == RESISTANCE)
hue = D1_R;
else
hue = D1_S;
break;
case PERIOD_H4:
thickness = 2;
style = STYLE_SOLID;
if (which == RESISTANCE)
hue = H4_R;
else
hue = H4_S;
break;
case PERIOD_H1:
style = STYLE_SOLID;
thickness = 1;
if (which == RESISTANCE)
hue = H1_R;
else
hue = H1_S;
break;
default:
style = STYLE_DASHDOTDOT;
thickness = 1;
if (which == RESISTANCE)
hue = M15_R;
else
hue = M15_S;
break;
}
if (ObjectFind(name) < 0)
{
if (which == SUPPORT)
ObjectCreate(name, OBJ_TREND, 0, array[p2][0], array[p2][2], array[p1][0], array[p1][2]);
else
ObjectCreate(name, OBJ_TREND, 0, array[p2][2], array[p2][3], array[p1][0], array[p1][3]);
}
ObjectSet(name, OBJPROP_COLOR, hue);
ObjectSet(name, OBJPROP_RAY, true);
ObjectSet(name, OBJPROP_BACK, true);
ObjectSet(name, OBJPROP_WIDTH, thickness);
ObjectSet(name, OBJPROP_STYLE, style);
if (which == SUPPORT)
{ // Lows (0 == Time)
ObjectMove (name, 0, array[p2][0], array[p2][2]);
ObjectMove (name, 1, array[p1][0], array[p1][2]);
}
else
{ // Highs
ObjectMove (name, 0, array[p2][0], array[p2][3]);
ObjectMove (name, 1, array[p1][0], array[p1][3]);
}
ObjectsRedraw();
return(0);
}
Comments