dsl_-_DMI_oscillator
Download scriptThis indicator is designed to track market momentum and trend direction by combining three distinct types of technical analysis: Directional Movement (DMI), Smoothing techniques, and Stochastic oscillators. It provides a visual representation of "market flow," helping traders identify which way the price is moving while filtering out minor noise.
Core Analytical Logic
1. Trend Detection (The Foundation) The script begins by calculating the directional movement of price. It looks at the distance between highs and lows over a specific period to determine if the market is pushing primarily upward or downward. Rather than just looking at raw price, it normalizes this movement against the "Average True Range" (the typical volatility of the asset). This allows the indicator to distinguish between a significant trend move and simple price vibration.
2. Smoothing and Filtering To ensure the data isn't too erratic for human interpretation, the script applies multiple layers of "smoothing." Users can choose between different mathematical averages (such as Simple, Exponential, Smoothed, or Linear Weighted). This means the indicator reacts to the general trend while ignoring short-term "hiccups" in price action.
3. Momentum & Level Crossing (The Oscillator) Once the directional trends are identified, the script calculates a momentum value similar to a Stochastic oscillator. This determines how fast the price is moving in its current direction.
A key feature here is the use of Dynamic Levels. Instead of relying on static boundaries, the script creates "Upper" and "Lower" boundary lines that adapt to the market's behavior. When the momentum value breaks significantly above these upper levels or below the lower levels, it confirms a stronger shift in trend intensity.
Visual Representation & Behavior
The indicator changes its visual output based on your preferences for how "signals" are triggered:
- Outer Level Cross: The indicator identifies a trend when the momentum moves past the adaptive boundary lines.
- Zero Cross: The indicator reacts whenever the momentum shifts from positive to negative (or vice versa).
- Slope Change: The indicator reacts based on the "angle" of the movement—detecting when the price starts to flatten out or pivot.
User Experience
On your chart, this logic manifests as a clean visual flow. It separates trend movements into distinct segments. By using a "cleaning" logic, the script ensures that the lines remain continuous and visually organized, automatically handling the transition points where the trend switches from one direction to another. This allows a trader to see at a glance whether the current market environment is bullish, bearish, or neutral.
//------------------------------------------------------------------
#property copyright "mladen"
#property link "mladenfx@gmail.com"
#property link "www.forex-station.com"
//------------------------------------------------------------------
#property indicator_separate_window
#property indicator_buffers 7
#property indicator_color1 clrDimGray
#property indicator_color2 clrDimGray
#property indicator_color3 clrDarkGray
#property indicator_color4 clrLimeGreen
#property indicator_color5 clrLimeGreen
#property indicator_color6 clrOrangeRed
#property indicator_color7 clrOrangeRed
#property indicator_style1 STYLE_DOT
#property indicator_style2 STYLE_DOT
#property indicator_width3 2
#property indicator_width4 3
#property indicator_width5 3
#property indicator_width6 3
#property indicator_width7 3
#property strict
//
//
//
//
//
enum enMaTypes
{
ma_sma, // Simple moving average
ma_ema, // Exponential moving average
ma_smma, // Smoothed MA
ma_lwma // Linear weighted MA
};
enum enColorOn
{
chg_onZero, // Change color on zero cross
chg_onOuter, // Change color on levels cross
chg_onSlope // Change color on slope change
};
input int DmiPeriod = 32; // DMI period
input enMaTypes DmiMaMethod = ma_smma; // DMI smoothing method
input int Smooth = 0; // Smothing period (<=1 for no smoothing)
input enMaTypes SmoothType = ma_ema; // Smothing method
extern int SignalPeriod = 9; // Signal period
input enColorOn ColorOn = chg_onOuter; // Change color on :
double stoch[],stochua[],stochub[],stochda[],stochdb[],levelu[],leveld[],state[];
//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//
int OnInit()
{
IndicatorBuffers(8);
SetIndexBuffer( 0, levelu);
SetIndexBuffer( 1, leveld);
SetIndexBuffer( 2, stoch);
SetIndexBuffer( 3, stochua);
SetIndexBuffer( 4, stochub);
SetIndexBuffer( 5, stochda);
SetIndexBuffer( 6, stochdb);
SetIndexBuffer( 7, state);
IndicatorShortName("DMI oscillator ("+(string)DmiPeriod+","+(string)Smooth+")");
return(0);
}
void OnDeinit(const int reason) { }
//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
int counted_bars = prev_calculated;
if(counted_bars < 0) return(-1);
if(counted_bars > 0) counted_bars--;
int limit=MathMin(rates_total-counted_bars,rates_total-1);
//
//
//
//
//
double alpha = 2.0/(1.0+SignalPeriod);
if (state[limit]== 1) CleanPoint(limit,stochua,stochub);
if (state[limit]==-1) CleanPoint(limit,stochda,stochdb);
for(int i=limit; i>=0; i--)
{
double dhh = (i<rates_total-1) ? high[i]-high[i+1] : 0;
double dll = (i<rates_total-1) ? low[i+1]-low[i] : 0;
double tr = (i<rates_total-1) ? MathMax(high[i],close[i+1])-MathMin(low[i],close[i+1]) : high[i]-low[i];
double atr = iCustomMa(DmiMaMethod,tr,DmiPeriod,i,rates_total,0);
double plusDM = (dhh>dll && dhh>0) ? dhh : 0;
double minusDM = (dll>dhh && dll>0) ? dll : 0;
double plusDI = 100*iCustomMa(DmiMaMethod,plusDM ,DmiPeriod,i,rates_total,1)/atr;
double minusDI = 100*iCustomMa(DmiMaMethod,minusDM,DmiPeriod,i,rates_total,2)/atr;
stoch[i] = iCustomMa(SmoothType,plusDI-minusDI,Smooth,i,rates_total,3);
levelu[i] = (i<Bars-1) ? (stoch[i]>0) ? levelu[i+1]+alpha*(stoch[i]-levelu[i+1]) : levelu[i+1] : 0;
leveld[i] = (i<Bars-1) ? (stoch[i]<0) ? leveld[i+1]+alpha*(stoch[i]-leveld[i+1]) : leveld[i+1] : 0;
switch(ColorOn)
{
case chg_onOuter : state[i] = (stoch[i]>levelu[i]) ? 1 : (stoch[i]<leveld[i]) ? -1 : 0; break;
case chg_onZero : state[i] = (stoch[i]>0) ? 1 : (stoch[i]<0) ? -1 : 0; break;
default : state[i] = (i<rates_total-1) ? (stoch[i]>stoch[i+1]) ? 1 : (stoch[i]<stoch[i+1]) ? -1 : state[i+1] : 0;
}
stochda[i] = EMPTY_VALUE;
stochdb[i] = EMPTY_VALUE;
stochua[i] = EMPTY_VALUE;
stochub[i] = EMPTY_VALUE;
if (state[i] == 1) PlotPoint(i,stochua,stochub,stoch);
if (state[i] == -1) PlotPoint(i,stochda,stochdb,stoch);
}
return(rates_total);
}
//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//
#define _maInstances 4
#define _maWorkBufferx1 1*_maInstances
#define _maWorkBufferx2 2*_maInstances
double iCustomMa(int mode, double price, double length, int r, int bars, int instanceNo=0)
{
r = bars-r-1;
switch (mode)
{
case ma_sma : return(iSma(price,(int)length,r,bars,instanceNo));
case ma_ema : return(iEma(price,length,r,bars,instanceNo));
case ma_smma : return(iSmma(price,(int)length,r,bars,instanceNo));
case ma_lwma : return(iLwma(price,(int)length,r,bars,instanceNo));
default : return(price);
}
}
//
//
//
//
//
double workSma[][_maWorkBufferx2];
double iSma(double price, int period, int r, int _bars, int instanceNo=0)
{
if (ArrayRange(workSma,0)!= _bars) ArrayResize(workSma,_bars); instanceNo *= 2; int k;
workSma[r][instanceNo+0] = price;
workSma[r][instanceNo+1] = price; for(k=1; k<period && (r-k)>=0; k++) workSma[r][instanceNo+1] += workSma[r-k][instanceNo+0];
workSma[r][instanceNo+1] /= 1.0*k;
return(workSma[r][instanceNo+1]);
}
//
//
//
//
//
double workEma[][_maWorkBufferx1];
double iEma(double price, double period, int r, int _bars, int instanceNo=0)
{
if (ArrayRange(workEma,0)!= _bars) ArrayResize(workEma,_bars);
workEma[r][instanceNo] = price;
if (r>0 && period>1)
workEma[r][instanceNo] = workEma[r-1][instanceNo]+(2.0/(1.0+period))*(price-workEma[r-1][instanceNo]);
return(workEma[r][instanceNo]);
}
//
//
//
//
//
double workSmma[][_maWorkBufferx1];
double iSmma(double price, double period, int r, int _bars, int instanceNo=0)
{
if (ArrayRange(workSmma,0)!= _bars) ArrayResize(workSmma,_bars);
workSmma[r][instanceNo] = price;
if (r>1 && period>1)
workSmma[r][instanceNo] = workSmma[r-1][instanceNo]+(price-workSmma[r-1][instanceNo])/period;
return(workSmma[r][instanceNo]);
}
//
//
//
//
//
double workLwma[][_maWorkBufferx1];
double iLwma(double price, double period, int r, int _bars, int instanceNo=0)
{
if (ArrayRange(workLwma,0)!= _bars) ArrayResize(workLwma,_bars);
workLwma[r][instanceNo] = price; if (period<=1) return(price);
double sumw = period;
double sum = period*price;
for(int k=1; k<period && (r-k)>=0; k++)
{
double weight = period-k;
sumw += weight;
sum += weight*workLwma[r-k][instanceNo];
}
return(sum/sumw);
}
//-------------------------------------------------------------------
//
//-------------------------------------------------------------------
//
//
//
//
//
void CleanPoint(int i,double& first[],double& second[])
{
if (i>=Bars-3) return;
if ((second[i] != EMPTY_VALUE) && (second[i+1] != EMPTY_VALUE))
second[i+1] = EMPTY_VALUE;
else
if ((first[i] != EMPTY_VALUE) && (first[i+1] != EMPTY_VALUE) && (first[i+2] == EMPTY_VALUE))
first[i+1] = EMPTY_VALUE;
}
void PlotPoint(int i,double& first[],double& second[],double& from[])
{
if (i>=Bars-2) return;
if (first[i+1] == EMPTY_VALUE)
if (first[i+2] == EMPTY_VALUE)
{ first[i] = from[i]; first[i+1] = from[i+1]; second[i] = EMPTY_VALUE; }
else { second[i] = from[i]; second[i+1] = from[i+1]; first[i] = EMPTY_VALUE; }
else { first[i] = from[i]; second[i] = EMPTY_VALUE; }
}
Comments