TradingView indicators

KDJ indicator on TradingView: formula and limits

KDJ starts with the close's position inside a recent high-low range, recursively smooths it into K and D, then calculates J = 3K - 2D. J can exceed 100 or fall below zero. To reproduce a KDJ chart, match the smoothing, initial values, first calculation bar, and flat-price rule as well as the familiar 9, 3, 3 settings.

RSV lookback: 9 barsK/D divisors: 3 / 3Seed: 50 / 50Flat window RSV: 50

A reproducible KDJ calculation

The 9, 3, 3 version uses the highest high H and lowest low L over nine chart bars, including the current bar. For a nonzero range, calculate RSV and update K before D:

RSV = 100 × (close - L) / (H - L)

K = (RSV + 2 × previous K) / 3

D = (current K + 2 × previous D) / 3

J = 3 × K - 2 × D

Moomoo documents these KDJ equations. This is recursive smoothing: a divisor of 3 assigns one third of the weight to the new input and two thirds to the previous result. It is not a three-observation simple average or a bicubic calculation.

Initialization and flat-price policy are part of the formula

The example below waits for N loaded bars, starts the previous K and D at 50, and uses RSV = 50 when H = L. These are explicit implementation choices. A zero seed, a first-RSV seed, a partial lookback window, or carrying the previous RSV on a flat window can all change the early values.

For example, with a first RSV of 100, a 50 seed gives K = 66.67 and D = 55.56. A zero seed gives K = 33.33 and D = 11.11. The same lengths do not imply the same series. With divisor 3 and identical subsequent RSV values, a difference in K decays by a factor of 2/3 per update; D also carries its own initial difference and the differences in K.

Worked example: J crosses 100 without K or D doing so

This is a hypothetical arithmetic fixture, not market data or a backtest. Assume each nine-bar window has H = 110, L = 100, and close = 110. RSV is 100. Start previous K = D = 50, keep both divisors at 3, and retain full precision between updates.

Valid updateRSVKDJ
110066.666755.555688.8889
210077.777862.9630107.4074
310085.185270.3704114.8148
410090.123576.9547116.4609

On update 2, J = 3 × 77.7778 - 2 × 62.9630, approximately 107.4074 before display rounding. J adds twice the K-D gap to K. It has no 0-to-100 clamp. Mirroring the fixture with RSV = 0 produces J = -7.4074 on update 2.

K and D stay between 0 and 100 under this script's assumptions: valid OHLC data, a seed in that interval, and smoothing divisors of at least 1. Each update is a weighted average of values in the interval. J uses subtraction, so the same bound does not apply.

Flat-window check

If all nine bars have high = low = close = 100, the script assigns RSV = 50. Starting from K = D = 50 leaves K, D, and J at 50. Following other price history, the same flat input moves K and D toward 50; it does not immediately reset them.

KDJ Pine Script v6 with explicit boundary rules

Open Pine Editor in TradingView, create an indicator, paste the complete source, save it, and select Add to chart. The script plots K in orange, D in green, and J in fuchsia. RSV is available in the Data Window for numerical comparison.

Pine Script v6

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Pineify
//@version=6
indicator("KDJ - explicit seed and flat-range rule", overlay = false)

length = input.int(9, "RSV lookback", minval = 1)
kLength = input.int(3, "K smoothing divisor", minval = 1)
dLength = input.int(3, "D smoothing divisor", minval = 1)

highestPrice = ta.highest(high, length)
lowestPrice = ta.lowest(low, length)
priceRange = highestPrice - lowestPrice
ready = bar_index >= length - 1 and not na(close) and not na(priceRange)

// Wait for N loaded bars. A flat window uses a neutral RSV of 50.
float rsv = ready ? (priceRange > 0 ? 100 * (close - lowestPrice) / priceRange : 50.0) : na

// Seed the previous K and D at 50 before the first valid update.
var float k = 50.0
var float d = 50.0
if ready
    k := (rsv + (kLength - 1) * k) / kLength
    d := (k + (dLength - 1) * d) / dLength

kValue = ready ? k : na
dValue = ready ? d : na
jValue = ready ? 3 * k - 2 * d : na

plot(kValue, "K", color.orange, linewidth = 2)
plot(dValue, "D", color.green, linewidth = 2)
plot(jValue, "J", color.fuchsia)
plot(rsv, "RSV", display = display.data_window)
hline(80, "Upper reference", color.gray)
hline(20, "Lower reference", color.gray)

// Evaluate crosses every bar; expose only confirmed chart-bar events.
crossUp = ta.crossover(kValue, dValue)
crossDown = ta.crossunder(kValue, dValue)
confirmedUp = barstate.isconfirmed and crossUp
confirmedDown = barstate.isconfirmed and crossDown
alertcondition(confirmedUp, "K crosses above D at close", "KDJ: K crossed above D on a closed chart bar.")
alertcondition(confirmedDown, "K crosses below D at close", "KDJ: K crossed below D on a closed chart bar.")

At length 9, the first eight loaded bars have no plotted KDJ values; the ninth receives the first recursive update. A length of 1 starts immediately, and a smoothing divisor of 1 passes the current input through. The 20 and 80 lines are visual references. They do not create orders.

Cross conditions require two valid plotted values, so the first output bar cannot produce a crossover alert. The code exposes confirmed crossover conditions for alerts; create an alert in TradingView and select the desired condition. It is an indicator, with no position sizing, exits, or performance report.

What each KDJ setting changes

InputExample defaultEffect and constraint
RSV lookback9 barsDefines the rolling high-low range. Minimum 1; outputs wait for this many loaded bars.
K smoothing divisor3New RSV weight is 1/divisor. A larger divisor retains more of the previous K. Minimum 1.
D smoothing divisor3New K weight is 1/divisor. A larger divisor retains more of the previous D. Minimum 1.

The lengths count chart bars, not fixed calendar days. Changing from a daily chart to an hourly chart changes the sampled data even when the inputs remain 9, 3, 3. There is no demonstrated best timeframe or asset-specific setting in this example.

For a controlled comparison, change one input, preserve the seed and zero-range policy, and compare the resulting series on identical bars. A parameter that creates more crossovers has not established better trade outcomes.

KDJ vs the traditional Stochastic oscillator

The shared RSV calculation does not make the smoothed lines interchangeable. TradingView's Stochastic documentation uses an SMA for %K smoothing and another SMA for %D.

CalculationThis KDJ exampleTradingView Stochastic
Range inputClose within the rolling high-low rangeClose within the rolling high-low range
K smoothingRecursive, new input weight 1/kLengthSMA of the raw stochastic value
D smoothingRecursive, new K weight 1/dLengthSMA of %K
Third lineJ = 3K - 2DNo J line in the documented formula
Parity requirementMatch seed, warmup, flat rule, and lengthsMatch SMA lengths and input series

Appending a J calculation to Stochastic creates a third line, but its K and D still follow the Stochastic smoothing rules. If two KDJ scripts disagree, compare their first valid RSV, K, and D in order before changing trading thresholds.

Read the Stochastic Pine Script guide

Read line values separately from trading decisions

ObservationWhat it establishesWhat remains unproven
K crosses above DK moved from at or below D to above DA profitable entry or a lasting price trend
J exceeds 100The positive K-D gap is large enough to push J above 100A reversal date or probability
K is above 80Smoothed RSV is near the upper end of its scaleThat price must fall next
A live crossover disappearsThe current bar changed before it closedThat a closed-bar alert fired

The live bar's high, low, and close can change. Pine rolls ordinary persistent variables back to their committed state before each realtime recalculation, so this script recomputes the current update from the previous bar rather than repeatedly smoothing every tick. See the execution model.

The alert conditions require barstate.isconfirmed, which TradingView defines as true on historical bars and the closing realtime update. The plotted live values remain provisional. This example uses only the chart timeframe; bar-state confirmation has separate limitations inside request.security().

  1. Compare identical symbols, sessions, timeframes, and loaded history. A different starting point changes the recursive seed history.
  2. Keep J unclipped when auditing calculations. Clamping it to 0 or 100 hides the behavior the third line is meant to display.
  3. Do not call the recursive smoother ta.sma. Matching a divisor of 3 alone does not match its weighting or seed.
  4. Separate an indicator check from a strategy test. Any entry rule still needs an exit, size, execution timing, fees, and slippage assumptions.

Educational calculation example, not investment advice. No return, accuracy, or reversal probability is established by these values.

Turn a KDJ specification into a checkable script

Pineify's Pine Script AI Coding Agent can help write or revise the indicator from a plain-language specification. Give it the calculation contract, not only the name KDJ.

Create a Pine Script v6 KDJ indicator with 9-bar RSV and recursive K/D smoothing divisors of 3. Wait for the full lookback, seed previous K and D at 50, and use RSV 50 on a zero-range window. Do not clamp J. Plot RSV in the Data Window and require chart-bar close for crossover alerts.
  1. Open the Pine Script AI Coding Agent and supply the specification.
  2. Compare the generated recurrence and boundary choices with the formula.
  3. Validate the source and add it to a TradingView chart.
  4. Check individual RSV, K, D, and J values before interpreting signals.
  5. Define exits, size, costs, and execution timing separately if you request a strategy.
Open Pine Script AI Coding Agent

KDJ questions

KDJ is a price-range momentum oscillator. It smooths the raw stochastic value into K, smooths K into D, and calculates J as 3K minus 2D. J magnifies the gap between K and D and can cross outside 0 to 100. A high J value describes the relationship between the lines; it does not establish that price will reverse.

For a nonzero lookback range, RSV = 100 × (close - lowest low) / (highest high - lowest low). With smoothing divisors of 3, K = (RSV + 2 × previous K) / 3 and D = (current K + 2 × previous D) / 3. J = 3K - 2D. A reproducible implementation must also specify the initial K/D values, first calculation bar, and zero-range rule.

They share the close-in-range calculation. The KDJ example uses recursive smoothing with a weight of 1 divided by the smoothing divisor. TradingView documents simple moving averages for its built-in Stochastic smoothing. Adding 3K - 2D to the built-in Stochastic therefore does not reproduce this KDJ implementation. Match the seed and the first valid bar as well as the lengths when comparing scripts.

J equals K + 2 × (K - D). When K is above D, the gap is added twice to K; when K is below D, it is subtracted twice. For example, K = 80 and D = 60 give J = 120, while K = 20 and D = 40 give J = -20. These are arithmetic examples, not trade signals or forecasts.

The raw RSV formula would divide by zero. This script substitutes RSV = 50 on a flat lookback window and continues the recursive updates. If K and D were already 50, all three lines remain 50. Other implementations may hold the previous RSV or return an unavailable value. Those choices can produce different later values even after the range becomes nonzero.

This example starts at 9, 3, 3 as a calculation reference. It does not establish the best settings for a market or timeframe. Changing the lookback changes the price range; increasing a smoothing divisor reduces the weight of the newest observation. Keep the initialization and flat-range rules fixed when comparing parameters, then test any trading rules separately with exits, position size, fees, and slippage.

Open Pine Editor, create an indicator script, replace its contents with the complete example, save it, and select Add to chart. K, D, and J appear in a separate pane. Check the three input values and use the Data Window to inspect RSV and the plotted values. The first output requires the configured number of loaded chart bars.

The live bar can change as its high, low, and close change. The script recalculates its lines on that bar, while its alert conditions require the chart bar to close. This distinguishes provisional line values from confirmed crossover events. It does not make data corrections, a different chart history, or changed inputs impossible. The example contains no higher-timeframe request or future-bar input.

Sources and calculation scope

Sources checked October 17, 2026. The seed, full-window warmup, zero-range policy, and hypothetical arithmetic fixtures are explicit choices of this example.

Compare more TradingView indicators