Pivot points and Fibonacci levels

Both are pre-computed support/resistance levels derived from prior price action — widely watched by enough intraday participants (especially in Indian index F&O) that they can become somewhat self-fulfilling.

Classic (Standard) Pivot Points — from the prior session's H/L/C

def classic_pivots(prev_high: float, prev_low: float, prev_close: float) -> dict:
    pivot = (prev_high + prev_low + prev_close) / 3
    r1 = 2 * pivot - prev_low
    s1 = 2 * pivot - prev_high
    r2 = pivot + (prev_high - prev_low)
    s2 = pivot - (prev_high - prev_low)
    r3 = prev_high + 2 * (pivot - prev_low)
    s3 = prev_low - 2 * (prev_high - pivot)
    return {"pivot": pivot, "r1": r1, "r2": r2, "r3": r3, "s1": s1, "s2": s2, "s3": s3}
def camarilla_pivots(prev_high: float, prev_low: float, prev_close: float) -> dict:
    rng = prev_high - prev_low
    return {
        "r1": prev_close + rng * 1.1/12, "r2": prev_close + rng * 1.1/6,
        "r3": prev_close + rng * 1.1/4,  "r4": prev_close + rng * 1.1/2,
        "s1": prev_close - rng * 1.1/12, "s2": prev_close - rng * 1.1/6,
        "s3": prev_close - rng * 1.1/4,  "s4": prev_close - rng * 1.1/2,
    }

Camarilla's R3/S3 (and R4/S4 as breakout confirmation levels) are specifically popular among Indian intraday index-options traders for range-bound day setups — a common pattern: fade R3/S3 as reversal levels, treat a break of R4/S4 as a trend-day breakout signal instead.

Fibonacci Retracement — from a defined swing high/low

def fibonacci_retracement(swing_high: float, swing_low: float) -> dict:
    diff = swing_high - swing_low
    levels = [0, 0.236, 0.382, 0.5, 0.618, 0.786, 1.0]
    return {f"fib_{lvl}": swing_high - diff * lvl for lvl in levels}

Fibonacci Extension — projecting beyond the original swing, for targets

def fibonacci_extension(swing_high: float, swing_low: float, retracement_point: float) -> dict:
    diff = swing_high - swing_low
    levels = [1.272, 1.618, 2.0, 2.618]
    return {f"ext_{lvl}": retracement_point + diff * lvl for lvl in levels}

The honest caveat on Fibonacci levels

Unlike pivot points (which are a pure, unambiguous arithmetic function of prior H/L/C), Fibonacci retracement requires *subjectively* choosing which swing high and swing low to measure from — two traders can draw completely different Fibonacci grids on the same chart. This subjectivity makes it far harder to backtest rigorously (chapter 82) or defend as a mechanical, reproducible signal — treat it as a discretionary tool for human chart reading rather than a candidate for an automated strategy unless you can define swing-point selection as an unambiguous algorithm first (e.g. a specific fractal/zigzag detection rule) and then validate that specific rule's results.

Automating swing-point selection, if you want Fibonacci in a bot

def find_swing_points(df: pd.DataFrame, order: int = 5) -> pd.DataFrame:
    """order: bars on each side that must be lower/higher for a point to count as a swing."""
    from scipy.signal import argrelextrema
    highs_idx = argrelextrema(df["high"].values, lambda a, b: a >= b, order=order)[0]
    lows_idx = argrelextrema(df["low"].values, lambda a, b: a <= b, order=order)[0]
    swings = pd.DataFrame(index=df.index)
    swings["swing_high"] = df["high"].iloc[highs_idx]
    swings["swing_low"] = df["low"].iloc[lows_idx]
    return swings

This makes swing selection mechanical and reproducible — a prerequisite for treating any Fibonacci-based signal as backtestable rather than purely discretionary.

Next: 112 — Computing all indicators in one pipeline