The Dual Volume Divergence Line (DVD/Line) is a sophisticated technical analysis tool designed to detect divergences between price and volume using two complementary volume indexes: the Positive Volume Index (PVI) and the Negative Volume Index (NVI). Its main goal is to provide early signals of potential trend reversals by analyzing volume behavior.
In addition to plotting a combined divergence line (DVD), the indicator also draws dynamic bands and labels bullish and bearish divergences — both regular and hidden — directly on the chart. This makes it a powerful visual aid for identifying trading opportunities.
The calculation starts with a typical price, obtained as the average of the high, low, and close for each bar. Based on this input, two indices are constructed:
Both indexes are smoothed using a weighted average, and their divergence from price is calculated. The difference between the PVI and NVI divergences forms the basis of the DVD Line, which reflects the directional pressure of volume.
This DVD Line is further compared to a linear regression to visually detect potential momentum shifts.
zaman: Sampling period for smoothing PVI/NVI (default: 17).genislik: Width for smoothing and band projection (default: 12).takip: Length for linear regression (default: 3).carpan: Multiplier to adjust indicator sensitivity.gosterBand: Toggle band visualization.gosterNormal: Show regular divergences (on/off).gosterGizli: Show hidden divergences (on/off).Ir: Divergence detection range.Ntype: Choose raw (Dvdi) or smoothed (DVD) data for divergence detection.Dvdi added to the typical price.Upper and lower bands are calculated using the Root Mean Square (RMS) of the highest and lowest DVD values over the smoothing window. These bands act as dynamic zones to evaluate extreme conditions and are rescaled to highlight outliers.
The indicator identifies two main types of divergences:
Divergences are detected by locating pivot points in both price and the selected oscillator (IrGo). When a new pivot is formed, it is compared to the previous one, and if a divergence condition is met, the appropriate label is drawn:
"Bull" for regular bullish divergence."hid.Bull" for hidden bullish divergence."Bear" for regular bearish divergence."hid.Bear" for hidden bearish divergence.All labels are offset using ATR to avoid overlapping with price bars.
The indicator works well across different timeframes, making it suitable for scalpers, intraday traders, and swing traders alike.
Here’s a breakdown of each adjustable parameter:
zaman (Sampling Period): Controls signal sensitivity. Lower values yield more signals but may be noisier.genislik (Band Width): Affects smoothing degree. Higher values result in smoother lines.takip (Trailing Length): Number of bars for linear regression, used for coloring the DVD Line.carpan (Multiplier): Adjusts how strongly PVI and NVI divergences influence the DVD Line.gosterBand: Enables/disables band visualization.gosterNormal and gosterGizli: Toggle the display of regular and hidden divergences.Ir: Sets the pivot detection range; higher values result in fewer but stronger signals.Ntype: Allows switching between raw (Dvdi) and smoothed (DVD) divergence sources.It is recommended to test different configurations based on the asset and timeframe to optimize the indicator’s performance.
// ------------------------------------------
// PRC_Dual Volume Divergence Line (DVD/Line)
//version = 0
//08.07.25
//Translated from TW by
//Iván González @ www.prorealcode.com
//Sharing ProRealTime knowledge
// ------------------------------------------
// --- Configuración de Parámetros
// ------------------------------------------
//zaman = 17 // Dvd Sampling Period
//genislik = 12 // Band Width
//takip = 3 // Trailing Length
//carpan = 1.0 // Multiplier
//gosterBand = 0 // 'Show Bands'
//gosterNormal = 1 // 'Show Normal Divergences'
//gosterGizli = 1 // 'Show Hidden Divergences'
//Ir = 1 // 'Divergence Range'
//Ntype = 1 // Divergence Selection True=smoothed (DVD); False raw (Dvdi)
// ------------------------------------------
// -- Cálculo del Indicador DVD
// ------------------------------------------
// --- Origen de datos ---
kaynak = (high + low + close) / 3
// --- Cálculo del Índice de Volumen Positivo (PVI)
IF barindex > 0 THEN
IF kaynak > kaynak[1] THEN
pvi = pvi[1] + (kaynak - kaynak[1])
ELSE
pvi = pvi[1]
ENDIF
ELSE
pvi = 0
ENDIF
// --- Señal y Divergencia PVI ---
pviSinyal = WeightedAverage[zaman](pvi)
pviIraksama = pvi - pviSinyal
// --- Cálculo del Índice de Volumen Negativo (NVI) ---
IF barindex > 0 THEN
IF kaynak < kaynak[1] THEN
nvi = nvi[1] - (kaynak - kaynak[1])
ELSE
nvi = nvi[1]
ENDIF
ELSE
nvi = 0
ENDIF
// --- Señal y Divergencia NVI ---
nviSinyal = WeightedAverage[zaman](nvi)
nviIraksama = nvi - nviSinyal
// --- Cálculo del DVD ---
Dvdi = (pviIraksama - nviIraksama) * carpan
Dvd = WeightedAverage[genislik](Dvdi + kaynak)
Dvd2 = LinearRegression[takip](Dvd)-LinearRegressionSlope[takip](Dvd) // ta.linreg(Dvd, takip, 1)
// --- Cálculo de Bandas ---
MaxDVD = Highest[genislik](Dvd)
MinDVD = Lowest[genislik](Dvd)
// Implementación de la función RMS (Root Mean Square)
rmsMax = SQRT(Average[genislik](SQUARE(MaxDVD)))
rmsMin = SQRT(Average[genislik](SQUARE(MinDVD)))
Ust = rmsMax
Alt = rmsMin
Orta = (Alt + Ust) / 2
// Proyección de las bandas
Ust = 2 * Ust - Orta
Alt = 2 * Alt - Orta
// --- Variables para colorear las líneas ---
// Línea DVD principal
IF Dvd > Dvd2 THEN
Rdvd = 0
Gdvd = 230
Bdvd = 222
ELSE
Rdvd = 251
Gdvd = 0
Bdvd = 255
ENDIF
// Línea Media
IF Orta > Orta[1] THEN
Rorta = 0
Gorta = 230
Borta = 119
ELSE
Rorta = 282
Gorta = 82
Borta = 82
ENDIF
// -----------------------------------------------------------------------------\\
// -- Detección de Divergencias
// -----------------------------------------------------------------------------//
// --- Selección del Oscilador para Divergencia ---
IF Ntype = 1 THEN
IrGo = Dvdi
ELSE
IrGo = Dvd
ENDIF
// --- Detección de Puntos Pivote (con retraso necesario en ProBuilder) ---
pivotHighDetected = (IrGo[Ir] = HIGHEST[2 * Ir + 1](IrGo))
pivotLowDetected = (IrGo[Ir] = LOWEST[2 * Ir + 1](IrGo))
// --- Almacenamiento de valores de pivotes anteriores ---
ONCE lastPHprice = 0
ONCE lastPLprice = 0
ONCE lastPHosc = 0
ONCE lastPLosc = 0
once lastPHindex=-1
once lastPLindex=-1
ayiNormal=0
ayiGizli=0
bogaNormal=0
bogaGizli=0
// Actualizar valores del último Pivote ALTO
IF pivotHighDetected and lastPHindex <> barindex[ir] THEN
if lastPHindex<> -1 then
if high[Ir]>LastPHprice and IrGo[Ir]<lastPHosc then
ayiNormal = 1
endif
if high[Ir]<lastPHprice and IrGo[Ir]>lastPHosc then
ayiGizli = 1
endif
endif
lastPHprice = high[Ir]
lastPHosc = IrGo[Ir]
lastPHIndex=barindex[Ir]
ENDIF
// Actualizar valores del último Pivote BAJO
IF pivotLowDetected and lastPLindex<>barindex[Ir] THEN
if lastPLindex<>-1 then
if low[Ir]<lastPLprice and IrGo[Ir]>lastPLosc then
bogaNormal=1
endif
if low[Ir]<lastPLprice and IrGo[Ir]<lastPLosc then
bogaGizli=1
endif
endif
lastPLprice = low[Ir]
lastPLosc = IrGo[Ir]
lastPLindex = barindex[Ir]
ENDIF
// --- Dibujo de Etiquetas de Divergencia ---
atr=averagetruerange[14](close)
// Normal Alcista
IF gosterNormal AND bogaNormal THEN
DRAWTEXT("Bull", barindex[Ir], low[Ir] - 0.15*atr ) COLOURED("green")
ENDIF
// Oculta Alcista
IF gosterGizli AND bogaGizli THEN
DRAWTEXT("hid.Bull", barindex[Ir], low[Ir] - 0.15*atr) COLOURED("lime")
ENDIF
// Normal Bajista
IF gosterNormal AND ayiNormal THEN
DRAWTEXT("Bear", barindex[Ir], high[Ir] + 0.15*atr) COLOURED("red")
ENDIF
// Oculta Bajista
IF gosterGizli AND ayiGizli THEN
DRAWTEXT("hid.Bear", barindex[Ir], high[Ir] + 0.15*atr) COLOURED("orange")
ENDIF
// -----------------------------------------------------------------------------\\
// --- Salida de Datos (Plot)
// -----------------------------------------------------------------------------//
RETURN Ust COLOURED(255, 82, 82, gosterBand*128) STYLE(POINT, 2) AS "Upper Band", Alt COLOURED(0, 230, 119, gosterBand*128) STYLE(POINT, 2) AS "Lower Band", Dvd as "Dvd Line" coloured(Rdvd,Gdvd,Bdvd)style(line,3), orta as "Middle band"coloured(Rorta,Gorta,Borta,80)style(line,3)