#_i_3D_ADX
Download scriptThis script creates a unique visual tool called a 3D ADX Diagram. Unlike standard technical indicators that appear as simple lines on a chart, this script generates a multi-layered "fan" or "matrix" of data that helps traders visualize market trends and momentum across different time scales simultaneously.
How the Logic Works
The core concept of this tool is to stack multiple layers of Average Directional Index (ADX) data. Instead of looking at just one ADX period (like a standard 14-period setting), this script calculates a series of increasing periods and displays them as stacked rows in a vertical diagram.
1. The 3D Structure The "3D" aspect refers to how the information is organized on your screen:
- Horizontal Axis (X): Represents time, moving from left to right along your trading chart.
- Vertical Axis (Y): Represents different ADX calculations. Each row in the diagram corresponds to a different period setting (e.g., starting at a short period and increasing by a set step). This allows you to see how the trend behaves over short-term, medium-term, and long-term horizons all at once.
- Color Depth (Z): The color of the blocks changes based on the intensity or direction of the market movement, providing a visual "heat map" of price action.
2. Display Modes The script offers three distinct ways to interpret this data, depending on the user's preference:
- Trend Direction: This mode focuses on which way the market is leaning. It compares two components of the ADX (Plus DI and Minus DI). If the upward momentum is stronger, the diagram highlights in one color; if the downward momentum is dominant, it shifts to another.
- Absolute Value: This mode visualizes the sheer strength of the trend. It uses a color gradient to show the magnitude of the ADX curve. Lighter shades represent weaker trends, while darker/more intense colors represent stronger market movements.
- Acceleration (Speed): This is a more dynamic view. It calculates the "velocity" of price changes—essentially showing how fast the trend is speeding up or slowing down. It uses a color gradient to distinguish between rapid upward acceleration and rapid downward acceleration.
Visual Representation
Instead of lines, the tool draws "shields" (rectangular blocks). This creates a solid visual block that makes it much easier for the human eye to detect patterns like:
- Trend Consistency: If all rows in the stack are the same color/intensity, the trend is healthy across all timeframes.
- Divergence: If the top rows (long-term) show one trend while the bottom rows (short-term) show another, it may signal a potential reversal or transition in the market.
- Momentum Exhaustion: By looking at the "Acceleration" mode, traders can see if a move is losing steam before the price actually turns around.
//+---------------------------------------------------------------------+
//| #_i_3D_ADX.mq4 |
//| Copyright © 2009, TigraVK |
//| |
//|Èíäèêàòîð òåêóùèé òðåíä íà îñíîâå ADX â |
//|òðåõìåðíîé äèàãðàììå â îñíîâíîì îêíå ãðàôèêà òîðãîâîãî |
//|èíñòðóìåíòà. Ïîñòðî÷íî îòáðàæàþòñÿ íàïðàâëåíèÿ òðåíäà ñ ïîøàãîâî |
//|óâåëè÷èâàþùèìèñÿ ïåðèîäàìè. |
//| ðåçóëüòàòå ïîëó÷àåòñÿ òðåõìåðíàÿ êàðòèíêà âååðà ADX |
//|Â äàííîé âåðñèè èíäèêàòîðà âîçìîæíû ðåæèìû îòîáðàæåíèÿ |
//| - íàïðàâëåíèÿ òðåíäà ïî óðîâíÿì +DI è -DI; |
//| - àáñîëþòíîãî çíà÷åíèÿ êðèâîé MAIN; |
//| - ñêîðîñòè ðîñòà èëè ñíèæåíèÿ +DI îòíèñèòåëüíî -DI. |
//| |
//|Êîîðäèíàòà Õ íà äèàãðàììå - âðåìÿ â ôîðìàòå ãðàôèêà òîðãîâîãî |
//|èíñòðóìåíòà |
//|Êîîðäèíàòà Y íà äèàãðàììå - ñâåðõó âíèç ïîñëåäîâàòåëüíîå îòîáðàæåíèå |
//|ADX ñ ðàçëè÷íûìè ïàðàìåòðàìè |
//|Êîîðäèíàòà Z îòðàæåíà ðàçëè÷íûìè öâåòàìè â çàâèñèìîñòè îò ñèòóàöèè |
//|è ïîëîæåíèÿ êðèâûõ ADX â äàííîé âðåìåííÎé òî÷êå |
//+---------------------------------------------------------------------+
#property copyright "Copyright © 2009, TigraVK"
#property link "tigravk@yandex.ru"
#property indicator_chart_window
#include <stdlib.mqh>
#define ELEMENTS 80 //êîëè÷åñòâî îòîáðàæàåìûõ ñòðîê â äèàãðàììå
extern int IndMode = 0; //îäèí èç òðåõ ðåæèìîâ îòðèñîâêè äèàãðàìì: 0-Íàïðàâëåíèå;1-àáñîëþòíîå çíà÷åíèå;2-áàðîâàÿ ñêîðîñòü èçìåíåíèÿ
extern int Columns = 600; //Êîëè÷åñòâî îòîáðàæàåìûõ ñòîëáöîâ äèàãðàììû
extern int Width = 1; //Øèðèíà ñòîëáöà, â áàðàõ
extern int DrawShift = 0; //Ñìåùåíèå íóëåâîãî ñòîëáöà (â áàðàõ) îòíîñèòåëüíî ïðàâîé ãðàíèöû îêíà ãðàôèêà
//ïðèìåíÿåòñÿ â ñëó÷àå âûâîäà äâóõ êîïèé èíäèêàòîðà ñ ðàçíûìè ïàðàìåòðàìè â îäíî îêíî
//äëÿ èñêëþ÷åíèÿ âèçóàëüíûõ ïåðåñå÷åíèé äèàãðàìì
//Íàïðèìåð, äëÿ âûâîäà âòîðîé äèàãðàììû êîððåêòíî áóäåò óñòàíîâèòü DrawShift=Columns+4
//-- Íà÷àëüíûå ïàðàìåòðû iADX è ïðèðàùåíèå ïåðèîäà -----------
extern int ADXperiod = 3;
extern int ADXperiod_step = 5;
extern int Method = MODE_SMA;
extern int ADXappliedPrice = 0; //PRICE_CLOSE 0 Öåíà çàêðûòèÿ
//PRICE_OPEN 1 Öåíà îòêðûòèÿ
//PRICE_HIGH 2 Ìàêñèìàëüíàÿ öåíà
//PRICE_LOW 3 Ìèíèìàëüíàÿ öåíà
//PRICE_MEDIAN 4 Ñðåäíÿÿ öåíà, (high+low)/2
//PRICE_TYPICAL 5 Òèïè÷íàÿ öåíà, (high+low+close)/3
//PRICE_WEIGHTED 6 Âçâåøåííàÿ öåíà çàêðûòèÿ, (high+low+close+close)/4
//-------------------------------
#define COLUMNS_DOP 3 //êîë-âî äîïîëíèòåëüíûõ êîëîíîê â ìàññèâå ADX[][] (òèïà, âû÷èñëèòåëüíûé çàïàñ)
#define HEADER 6 //ìåñòî ïîä çàãîëîâîê (èçìåðÿåòñÿ âûñîòîé ýëåìåòà äèàãðàììû)
#define GAP 0 //ïðîáåë (â áàðàõ) ìåæäó ýëåìåíòàìè äèàãðàììû â ãîðèçîíòàëè
#define GAP_PERCENT 20 //ïðîáåë (â ïðîöåíòàõ îò âûñîòû ýëåìåíòà äèàãðàììû) ìåæäó ýëåìåíòàìè äèàãðàììû â âåðòèêàëè
double ADXMAIN[][ELEMENTS];//ìàññèâ êàðòà êðèâîé MAIN
double ADXPLUS[][ELEMENTS];//ìàññèâ êàðòà êðèâîé +DI
double ADXMINUS[][ELEMENTS];//ìàññèâ êàðòà êðèâîé -DI
double Top;
double Bottom;
int FreeBars;
string el_name;
string indname = "#_i_3D_ADX";
datetime tm;
int shift;
//+------------------------------------------------------------------+
int init()
{
tm=Time[0];
shift=DrawShift*(Width+GAP);
Top =WindowPriceMax(0);
Bottom =WindowPriceMin(0);
FreeBars=WindowBarsPerChart()-WindowFirstVisibleBar()-shift;
if(IndMode==0)
{
el_name = "ADXDIR";
CreateHeader("ADX direction", Top, Width, Columns, FreeBars, Yellow);
}
else if(IndMode==1)
{
el_name = "ADXABS";
CreateHeader("ADX absolute", Top, Width, Columns, FreeBars, Yellow);
}
else if(IndMode==2)
{
el_name = "ADXACC";
CreateHeader("ADX acceleration", Top, Width, Columns, FreeBars, Yellow);
}
else
{
el_name = "ADX";
CreateHeader("NONE", Top, Width, Columns, FreeBars, Yellow);
}
IndicatorShortName(indname);
ArrayResize(ADXMAIN,Columns+COLUMNS_DOP);
ArrayInitialize(ADXMAIN, 0.0);
ArrayResize(ADXPLUS,Columns+COLUMNS_DOP);
ArrayInitialize(ADXPLUS, 0.0);
ArrayResize(ADXMINUS,Columns+COLUMNS_DOP);
ArrayInitialize(ADXMINUS, 0.0);
//ñîçäàåì êâàäðàòèêè
for(int i=0; i<Columns; i++)
CreateShield(el_name+i+"_", Top, Bottom, Width, FreeBars-(Width+GAP)*i, Gray);
return(0);
}
//+------------------------------------------------------------------+
int deinit()
{
DeleteIndicatorObject(el_name);
return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int start()
{
int i;
int limit;
double top =WindowPriceMax(0);
double bottom =WindowPriceMin(0);
int free_bars =WindowBarsPerChart()-WindowFirstVisibleBar()-shift;
int counted_bars=IndicatorCounted();
limit=Bars-counted_bars;
if(limit>Columns+COLUMNS_DOP) limit=Columns+COLUMNS_DOP;
//Ïðîöåäóðà ïåðåðèñîâêè äèàãðàììû ïðè ñìåíå òåêóùåãî áàðà èëè ðàçìåðîâ ýêðàííîé îáëàñòè ãðàôèêà
if(Top!=top || Bottom!=bottom || FreeBars!=free_bars || tm!=Time[0])
{
Top=top; Bottom=bottom; FreeBars=free_bars; tm=Time[0];
for(i=0; i<Columns; i++)
{
if(MoveShield(el_name+i+"_", Top, Bottom, Width, FreeBars-(Width+GAP)*i)<0)
{
DeleteIndicatorObject(el_name+i+"_");
CreateShield(el_name+i+"_", Top, Bottom, Width, FreeBars-(Width+GAP)*i, Gray);
}
}
MoveHeader(Top, Width, Columns, FreeBars, Yellow);
}
if(limit>=Columns+COLUMNS_DOP) //ïîëíàÿ îòðèñîâêà ïðè çàïóñêå èíäèêàòîðà
{
AdxDATA_fill(ADXMAIN, ADXPLUS, ADXMINUS, limit, 0, 0);
if(IndMode==0) AdxWeerDirection(ADXPLUS, ADXMINUS, Columns);
else if(IndMode==1) AdxWeerAbsolute(ADXMAIN, Columns);
else if(IndMode==2) AdxWeerAcceleration(ADXPLUS, ADXMINUS, Columns);
}
else if(limit>1 && limit<Columns+COLUMNS_DOP) //ïåðåðèñîâêà ïðè ñìåíå áàðà
{
AdxDATA_leftShift(ADXMAIN, ADXPLUS, ADXMINUS, Columns+COLUMNS_DOP, limit-1);
AdxDATA_fill(ADXMAIN, ADXPLUS, ADXMINUS, limit-1, 0, 0);
if(IndMode==0) AdxWeerDirection(ADXPLUS, ADXMINUS, Columns);
else if(IndMode==1) AdxWeerAbsolute(ADXMAIN, Columns);
else if(IndMode==2) AdxWeerAcceleration(ADXPLUS, ADXMINUS, Columns);
}
else //ïåðåðèñîâêà òîëüêî òåêóùåãî áàðà
{
AdxDATA_fill(ADXMAIN, ADXPLUS, ADXMINUS, limit, 0, 0);
if(IndMode==0) AdxWeerDirection(ADXPLUS, ADXMINUS, limit);
else if(IndMode==1) AdxWeerAbsolute(ADXMAIN, limit);
else if(IndMode==2) AdxWeerAcceleration(ADXPLUS, ADXMINUS, Columns);
}
err("Start: ");
return(0);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
void AdxDATA_fill(double& MAIN[][], double& PDI[][], double& MDI[][], int recount_columns, int start_columns, int historyBarShift)
{
int i,j;
int adxp;
for(j=start_columns; j<recount_columns+start_columns; j++)
{
adxp=ADXperiod;
for(i=0; i<ELEMENTS; i++)
{
PDI[j][i] =iADX(NULL,0,adxp,ADXappliedPrice,MODE_PLUSDI,j+historyBarShift);
MDI[j][i] =iADX(NULL,0,adxp,ADXappliedPrice,MODE_MINUSDI,j+historyBarShift);
MAIN[j][i]=iADX(NULL,0,adxp,ADXappliedPrice,MODE_MAIN,j+historyBarShift);
adxp=adxp+ADXperiod_step;
}
}
return;
}
//+------------------------------------------------------------------+
void AdxDATA_leftShift(double& MAIN[][], double& PDI[][], double& MDI[][], int columns, int shift_columns_count)
{
int i,j,k;
for(k=1; k<=shift_columns_count; k++)
{
for(j=columns-1; j>0; j--)
{
for(i=0; i<ELEMENTS; i++)
{
MAIN[j][i] = MAIN[j-1][i];
PDI[j][i] = PDI[j-1][i];
MDI[j][i] = MDI[j-1][i];
}
}
for(i=0; i<ELEMENTS; i++)
{
MAIN[j][i] = 0.0;
PDI[j][i] = 0.0;
MDI[j][i] = 0.0;
}
}
}
//+------------------------------------------------------------------+
// çåëåíûé öâåò, åñëè +DI âûøå -DI
// êðàñíûé öâåò, åñëè -DI âûøå +DI
void AdxWeerDirection(double& PDI[][], double& MDI[][], int recount_columns)
{
int i,j;
for(j=recount_columns-1; j>=0; j--)
{
for(i=0; i<ELEMENTS; i++)
{
if(PDI[j][i]-MDI[j][i]>=0.0) ObjectSet(el_name+DoubleToStr(j,0)+"_"+i, OBJPROP_COLOR, LightGreen);
else ObjectSet(el_name+DoubleToStr(j,0)+"_"+i, OBJPROP_COLOR, Red);
}
}
}
//+------------------------------------------------------------------+
// àáñîëþòíîå çíà÷åíèå âûâîäèòñÿ â ãðàäàöèè îò áåëîãî (ìèíèìóì) äî çåëåíîãî(ìàêñèìóì)
// Ìàêñèìóì íîðìèðóåòñÿ ê ìàêñèìàëüíîìó çíà÷åíèþ êðèâîé çà èññëåäóåìûé ïåðèîä èñòîðèè
void AdxWeerAbsolute(double& DATA[][], int columns)
{
int i,j;
color clr;
double min, max;
for(i=0; i<ELEMENTS; i++)
{
min=10000;
max=-10000;
for(j=0; j<columns; j++)
{
min=MathMin(min, MathAbs(DATA[j][i]));
max=MathMax(max, MathAbs(DATA[j][i]));
}
for(j=0; j<columns; j++)
{
clr = ColorGradient(DATA[j][i], min, max, 1); //çåëåíûé
ObjectSet(el_name+j+"_"+i, OBJPROP_COLOR, clr);
}
}
}
//+------------------------------------------------------------------+
void AdxWeerAcceleration(double& PDI[][], double& MDI[][], int columns)
{
int i,j;
color clr;
double max_vel;
double VEL[][ELEMENTS];
ArrayResize(VEL, columns);
//Íàðèñóåì ìàòðèöó òåêóùèõ ðàçíîñòåé +DI è -DI
for(j=columns-1; j>=0; j--)
for(i=0; i<ELEMENTS; i++)
VEL[j][i]=PDI[j][i]-MDI[j][i];
//çà ïåðèîä Columns ñàìàÿ ñèëüíàÿ àáñîëþòíàÿ áàðîâàÿ ñêîðîñòü
for(i=0; i<ELEMENTS; i++)
{
max_vel=-10000;
for(j=0; j<columns; j++)
max_vel=MathMax(max_vel, MathAbs(VEL[j][i]));
//Ñêîðîñòü âíèç - êðàñíûé ãðàäèåíò; ñêîðîñòü ââåðõ - çåëåíûé
for(j=0; j<columns; j++)
{
if(VEL[j][i]>=0)
{
clr = ColorGradient(VEL[j][i], 0, max_vel, 1); //çåëåíûé
ObjectSet(el_name+j+"_"+i, OBJPROP_COLOR, clr);
}
else
{
clr = ColorGradient(-VEL[j][i], 0, max_vel, 0); //êðàñíûé
ObjectSet(el_name+j+"_"+i, OBJPROP_COLOR, clr);
}
}
}
}
//+------------------------------------------------------------------+
color ColorGradient(double current_vol, double min_vol, double max_vol, int maincolor)
{
int R,G,B;
int cur;
if(current_vol<min_vol) current_vol=min_vol;
if(current_vol>max_vol) current_vol=max_vol;
cur = 255-255*(current_vol-min_vol)/(max_vol-min_vol);
if(maincolor==0) //RED
{ R=255; G=cur; B=cur; }
else if(maincolor==1) //GREEN
{ R=cur; G=255; B=cur; }
else if(maincolor==2) //BLUE
{ R=cur; G=cur; B=255; }
else {R=0;G=0;B=0;}
G<<=8;
B<<=16;
return(R+G+B);
}
//+------------------------------------------------------------------+
void CreateShield(string name_mask, double top, double bottom, int width, int freebars, color clr)
{
double high, gap, y1, y2;
datetime fut0, fut1;
high = (top-bottom)/(ELEMENTS*1.0);
gap= high*GAP_PERCENT/100.0;
bottom=bottom+gap;
top=top-HEADER*high;
high = (top-bottom)/(ELEMENTS*1.0);
gap= high*GAP_PERCENT/100.0;
high=high-gap;
if(freebars>0)
{
fut0=Time[0]+Period()*freebars*60;
fut1=Time[width]+Period()*freebars*60;
}
else
{
fut0=iTime(NULL,0,-freebars);
fut1=iTime(NULL,0,-freebars+width);
}
y2=top;
for(int i=0; i<ELEMENTS; i++)
{
y1=y2-gap;
y2=y1-high;
ObjectCreate(name_mask+i, OBJ_RECTANGLE, 0, fut0, y1, fut1, y2);
ObjectSet(name_mask+i, OBJPROP_COLOR, clr);
}
return;
}
//+------------------------------------------------------------------+
int MoveShield(string name_mask, double top, double bottom, int width, int freebars)
{
double high, gap, y1, y2;
datetime fut0, fut1;
high = (top-bottom)/(ELEMENTS*1.0);
gap= high*GAP_PERCENT/100.0;
bottom=bottom+gap;
top=top-HEADER*high;
high = (top-bottom)/(ELEMENTS*1.0);
gap= high*GAP_PERCENT/100.0;
high=high-gap;
if(freebars>0)
{
fut0=Time[0]+Period()*freebars*60;
fut1=Time[width]+Period()*freebars*60;
}
else
{
fut0=iTime(NULL,0,-freebars);
fut1=iTime(NULL,0,-freebars+width);
}
y2=top;
for(int i=0; i<ELEMENTS; i++)
{
y1=y2-gap;
y2=y1-high;
if(ObjectMove(name_mask+i, 0, fut0, y1)==false) return(-1);
ObjectMove(name_mask+i, 1, fut1, y2);
}
return(0);
}
//+------------------------------------------------------------------+
void CreateHeader(string text, double top, int width, int columns, int freebars, color clr)
{
datetime time_center;
int allbars;
if(freebars<0) {Print("ERROR CreateHeader: freebars<0"); return;}
allbars = columns*(width+GAP); //ñòîëüêî íóæíî áàðîâ ïîä äèàãðàììó
if(allbars/2<freebars) //öåíòð çàãîëîâêà óìåùàåòñÿ â çîíå çà ãðàôèêîì ñïðàâà
time_center=Time[0] + 60*Period()*(freebars - columns*(width+GAP)/2);
else //îòðèñîâêà ÷àñòè÷íî çàõâàòûâàåò èñòîðè÷åñêóþ çîíó
time_center = iTime(NULL, 0, allbars/2-freebars);
ObjectCreate(el_name+"_HEAD", OBJ_TEXT, 0, time_center, top);
ObjectSetText(el_name+"_HEAD", text, 12, "Areal", clr);
return;
}
//+------------------------------------------------------------------+
void MoveHeader(double top, int width, int columns, int freebars, color clr)
{
datetime time_center;
int allbars;
if(freebars<0) {Print("ERROR CreateHeader: freebars<0"); return;}
allbars = columns*(width+GAP); //ñòîëüêî íóæíî áàðîâ ïîä äèàãðàììó
if(allbars/2<freebars) //öåíòð çàãîëîâêà óìåùàåòñÿ â çîíå çà ãðàôèêîì ñïðàâà
time_center=Time[0] + 60*Period()*(freebars - columns*(width+GAP)/2);
else //îòðèñîâêà ÷àñòè÷íî çàõâàòûâàåò èñòîðè÷åñêóþ çîíó
time_center = iTime(NULL, 0, allbars/2-freebars);
ObjectMove(el_name+"_HEAD", 0, time_center, top);
}
//+------------------------------------------------------------------+
void DeleteIndicatorObject(string mask)
{
int obj_total, i, out;
string name;
out=1;
while(out>0)
{
obj_total=ObjectsTotal();
out=0;
for(i=0;i<obj_total;i++)
{
name = ObjectName(i);
if(StringFind(name,mask)>=0) { ObjectDelete(name); out++; }
}
}
}
//+------------------------------------------------------------------+
void err(string name)
{
int err=GetLastError();
if(err!=0) Print(name," ERROR(",err,"): ",ErrorDescription(err));
}
Comments