adx: Configurable ADX (library) 
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © t92a4

//@version=5

// @description Calculate ADX (and its constituent parts +DI, -DI, ATR), 
// using different moving averages and periods. 
library("adx", overlay=false)

ma(simple string type, float src, simple int len) =>
    if type == "RMA" 
        ta.rma(src, len)
    else if type == "SMA"
        ta.sma(src, len)
    else if type == "EMA"
        ta.ema(src, len)
    else if type == "WMA"
        ta.wma(src, len)
    else if type == "HMA"
        ta.hma(src, len)
    else if type == "LSMA"
        ta.linreg(src, len, 0)
    else
        runtime.error(str.format("adx.ma(): unknown type {0}", type))
        na

// @description Calculate ADX (and its constituent parts +DI, -DI, ATR), 
// using different moving averages and periods.
//
// @returns [ATR, +DI, -DI, ADX]
//
// @param atrMA Moving Average used for calculating the Average True Range. 
// Traditionally RMA, but using SMA here and in adxMA gives good results too.
//
// @param diMA Moving Average used for calculating the Directional Index. 
// Traditionally, RMA.
//
// @param adxMA Moving Average used for calculating the Average Directional 
// Index. Traditionally RMA, but using SMA here and in atrMA gives good results 
// too.
//
// @param atrLen Length of the Average True Range.
//
// @param diLen Length of the Directional Index.
//
// @param adxLen Length (smoothing) of the Average Directional Index.
//
// @param h Candle's high.
//
// @param l Candle's low.
//
// @param c Candle's close.
export adx(
  simple string atrMA="RMA",
  simple string diMA="RMA",
  simple string adxMA="RMA",
  simple int atrLen=14,
  simple int diLen=14,
  simple int adxLen=14, 
  float h=high, 
  float l=low, 
  float c=close) =>
	float ch  = ta.change(h)
    float cl  = -ta.change(l)
    float dmp = na(ch) ? na : (ch > cl and ch > 0 ? ch : 0)
    float dmm = na(cl) ? na : (cl > ch and cl > 0 ? cl : 0)
    float tr  = math.max(h - l, math.abs(h - c[1]), math.abs(l - c[1]))
    float atr = ma(atrMA, tr, atrLen)
    float dip = fixnan(100 * ma(diMA, dmp, diLen) / atr)
    float dim = fixnan(100 * ma(diMA, dmm, diLen) / atr)
    float sum = dip + dim
    float adx = 100 * ma(adxMA, math.abs(dip - dim) / (sum == 0 ? 1 : sum), adxLen)
    [atr, dip, dim, adx]

/// USAGE

string ATR_MA = input.string("RMA", "ATR Moving Average", 
  options=["RMA", "SMA", "EMA", "WMA", "HMA", "LSMA"],
  tooltip="Traditionally RMA, but using SMA here and in ADX gives good results too.")
string DI_MA = input.string("RMA", "DI Moving Average",
  options=["RMA", "SMA", "EMA", "WMA", "HMA", "LSMA"],
  tooltip="Traditionally RMA.")
string ADX_MA = input.string("RMA", "ADX Moving Average", 
  options=["RMA", "SMA", "EMA", "WMA", "HMA", "LSMA"],
  tooltip="Traditionally RMA, but using SMA here and in ATR gives good results too.")
int ATR_LEN = input.int(14, "ATR Length", tooltip="Normally the same as the DI length")
int DI_LEN = input.int(14, "DI Length", tooltip="Normally the same as the ATR length")
int ADX_LEN = input.int(14, "ADX Length", tooltip="Also known as ADX Smoothing")
float H = input.source(high, "High")
float L = input.source(low, "Low")
float C = input.source(close, "Close")

[atr, dip, dim, adx] = adx(
  atrMA=ATR_MA, diMA=DI_MA, adxMA=ADX_MA, 
  atrLen=ATR_LEN, diLen=DI_LEN, adxLen=ADX_LEN, 
  h=H, l=L, c=C)

plot(atr, "ATR", color.blue, display=display.none)
plot(adx, "ADX", color.purple, linewidth=2)
plot(dip, "+DI", color.lime)
plot(dim, "-DI", color.red)
hline(25)
