Stochastic Oscillator

Haiyue
9min

I. What is the Stochastic Oscillator

The Stochastic Oscillator is a momentum oscillator that measures momentum by comparing the current closing price to its position within the price range over a given period. The core idea is: in an uptrend, closing prices tend to be near the high of the range; in a downtrend, closing prices tend to be near the low of the range.

Historical Background

The Stochastic Oscillator was invented by Dr. George Lane in the 1950s. Lane was a prominent technical analyst at the Chicago Board of Trade who observed that “momentum changes before price” and quantified this principle into the Stochastic indicator. It became extremely popular among short-term traders for its ability to sensitively capture price turning points.

Indicator Classification

  • Type: Oscillator, displayed in a separate panel
  • Category: Momentum
  • Default Parameters: %K period =14= 14, %K smoothing =3= 3, %D period =3= 3
  • Value Range: 0 — 100
Fast vs Slow Stochastic
  • Fast Stochastic: Raw %K and its SMA (%D); signals are very sensitive but noisy
  • Slow Stochastic: Apply SMA(3) smoothing to Fast %K to get Slow %K, then apply SMA(3) to Slow %K to get Slow %D; this is the more commonly used version in practice

II. Mathematical Principles and Calculation

Core Formulas

Step 1: Calculate Fast %K (raw stochastic value)

%Kfast=CtLL14HH14LL14×100\%K_{fast} = \frac{C_t - LL_{14}}{HH_{14} - LL_{14}} \times 100

Where:

  • CtC_t = current closing price
  • LL14LL_{14} = lowest low over the past 14 periods
  • HH14HH_{14} = highest high over the past 14 periods

Step 2: Calculate Slow %K

%Kslow=SMA(%Kfast,3)\%K_{slow} = SMA(\%K_{fast}, 3)

That is, a 3-period simple moving average of Fast %K.

Step 3: Calculate %D (Signal Line)

%D=SMA(%Kslow,3)\%D = SMA(\%K_{slow}, 3)

That is, a 3-period simple moving average of Slow %K.

Step-by-Step Calculation Logic

  1. Determine lookback period: Default 14 periods
  2. Find range extremes: Calculate the highest high and lowest low over the past 14 periods
  3. Calculate raw %K: Percentage position of the closing price within the range
  4. First smoothing: SMA(3) to get Slow %K
  5. Second smoothing: SMA(3) to get %D

Intuitive Understanding

If the 14-day price range is [90,110][90, 110] and the current closing price is 105105:

%K=1059011090×100=75%\%K = \frac{105 - 90}{110 - 90} \times 100 = 75\%

This means the current price is at the 75% position of the range — on the higher side but not yet at an extreme level.

About the %K and %D Naming

George Lane originally labeled the two lines with the letters K and D, without any special abbreviation meaning. In the Chinese market, the Stochastic is often modified with RSV into the KDJ indicator (adding J line = 3%K - 2%D).


III. Python Implementation

import numpy as np
import pandas as pd


def stochastic(high: pd.Series,
               low: pd.Series,
               close: pd.Series,
               k_period: int = 14,
               k_smooth: int = 3,
               d_smooth: int = 3) -> pd.DataFrame:
    """
    Calculate the Stochastic Oscillator (Slow version)

    Parameters
    ----------
    high : pd.Series
        High price series
    low : pd.Series
        Low price series
    close : pd.Series
        Close price series
    k_period : int
        %K lookback period, default 14
    k_smooth : int
        %K smoothing period (Fast->Slow), default 3
    d_smooth : int
        %D smoothing period, default 3

    Returns
    -------
    pd.DataFrame
        DataFrame with Slow %K and %D columns
    """
    # Calculate range highs and lows
    lowest_low = low.rolling(window=k_period, min_periods=k_period).min()
    highest_high = high.rolling(window=k_period, min_periods=k_period).max()

    # Fast %K
    fast_k = (close - lowest_low) / (highest_high - lowest_low) * 100

    # Slow %K = SMA(Fast %K)
    slow_k = fast_k.rolling(window=k_smooth, min_periods=k_smooth).mean()

    # %D = SMA(Slow %K)
    d = slow_k.rolling(window=d_smooth, min_periods=d_smooth).mean()

    return pd.DataFrame({
        "Slow_K": slow_k,
        "D": d
    }, index=close.index)


# ========== Usage Example ==========
if __name__ == "__main__":
    np.random.seed(42)
    dates = pd.date_range("2024-01-01", periods=120, freq="D")
    base = 100 + np.cumsum(np.random.randn(120) * 1.0)

    df = pd.DataFrame({
        "date": dates,
        "open":  base + np.random.randn(120) * 0.3,
        "high":  base + np.abs(np.random.randn(120) * 1.0),
        "low":   base - np.abs(np.random.randn(120) * 1.0),
        "close": base,
        "volume": np.random.randint(1000, 10000, size=120),
    })
    df.set_index("date", inplace=True)

    # Calculate Stochastic
    stoch = stochastic(df["high"], df["low"], df["close"])
    df = pd.concat([df, stoch], axis=1)

    print("=== Stochastic Results (last 15 rows) ===")
    print(df[["close", "Slow_K", "D"]].tail(15).to_string())

    # Overbought/Oversold signals
    df["signal"] = np.where(
        (df["Slow_K"] > 80) & (df["D"] > 80), -1,   # Overbought
        np.where(
            (df["Slow_K"] < 20) & (df["D"] < 20), 1, 0  # Oversold
        )
    )

    # Crossover signals
    df["k_above_d"] = (df["Slow_K"] > df["D"]).astype(int)
    df["cross"] = df["k_above_d"].diff()
    golden = df[df["cross"] == 1]
    death = df[df["cross"] == -1]

    print("\n=== Bullish Cross (%K crosses above %D) ===")
    print(golden[["close", "Slow_K", "D"]].head(10).to_string())

IV. Problems the Indicator Solves

1. Overbought / Oversold Detection

ZoneConditionMeaning
Overbought%K and %D both > 80Price near range top, pullback probability increases
Oversold%K and %D both < 20Price near range bottom, bounce probability increases

2. %K / %D Crossover Signals

  • %K crosses above %D (more effective in oversold zone) — Buy signal
  • %K crosses below %D (more effective in overbought zone) — Sell signal

3. Divergence Signals

  • Bearish Divergence: Price makes a new high, but Stochastic does not — upward momentum is exhausted
  • Bullish Divergence: Price makes a new low, but Stochastic does not — downward momentum is exhausted

4. Bull/Bear Dividing Line

George Lane emphasized that %K or %D crossing the 50 midline also carries significance:

  • Operating above 50 — price tends to be in the upper half of the range, bullish bias
  • Operating below 50 — price tends to be in the lower half of the range, bearish bias
Caution

In strong one-directional moves, the Stochastic can remain saturated in overbought or oversold territory for extended periods. Avoid counter-trend trading during these times; wait for the indicator to leave the extreme zone before acting on crossover signals.


V. Advantages, Disadvantages, and Use Cases

Advantages

AdvantageDescription
Highly responsiveBased on price position within range, reacts quickly to turning points
Intuitive signalsOverbought/oversold + crossover signals are clear and easy to understand
Uses H/L/C dataIncorporates both high and low prices, richer information dimension
Suited for short-termHigh accuracy in range-bound oscillating markets

Disadvantages

DisadvantageDescription
Saturation in trendsStays at extreme levels during strong trends, signals become invalid
NoisyEven the Slow version produces noise; Fast Stochastic signals are overly frequent
Range dependentWhen price breaks out of historical range, indicator stays at extremes
Lags momentumCrossover signals may lag behind the optimal entry point

Use Cases

  • Range-bound markets: The ideal application scenario for Stochastic
  • Short-term trading: Intraday or multi-day swing operations
  • Combined with trend filter: In uptrends, only focus on oversold buy signals; in downtrends, only focus on overbought sell signals
ComparisonStochasticRSIWilliams %R
Price DataH/L/CClose onlyH/L/C
SensitivityHighMediumHigh (equivalent)
SmoothingDual SMA smoothingWilder SmoothingNone
Value Range0-1000-100-100 to 0
Practical Tips
  1. Wait for crossover in oversold zone: Do not buy when %K just enters the oversold zone; wait for %K to cross above %D before acting.
  2. Filter with ADX: When ADX < 25 (no clear trend), Stochastic signals are most reliable.
  3. Multi-timeframe alignment: Weekly Stochastic oversold + daily Stochastic bullish cross = strong buy signal.
  4. Watch %K slope: Rapid %K changes indicate strong momentum; slow changes indicate weakening momentum.