{
  "indicator": "RSI divergence detector: Wilder RSI with divergences confirmed on closed swing pivots",
  "slug": "rsi-divergence",
  "existingPage": {
    "canonicalUrl": "https://brokercheck.co/rsi-divergence-indicator/",
    "slug": "rsi-divergence-indicator",
    "sourceSnapshot": "source/post.rest.json and source/rsi-divergence-indicator.html (saved 2026-09-24 at 12:58 UTC, post last modified 2026-09-18)",
    "reuse": "URL, slug and topic structure only. Existing images are not reused, edited or redrawn. Claims without support are omitted or qualified."
  },
  "language": "en",
  "audience": "Retail chart users who want to know exactly what an RSI divergence tool flags, when it flags it, and where it fails",
  "inputs": {
    "RsiPeriod": 14,
    "appliedPrice": "close (fixed, not an input)",
    "PivotLeftBars": 5,
    "PivotRightBars": 5,
    "MinPivotDistance": 5,
    "MaxPivotDistance": 60,
    "ShowHidden": false,
    "levels": "30 and 70 drawn as reference lines only; no overbought/oversold filter is applied"
  },
  "formula": {
    "change": "change[i] = close[i] - close[i-1] for i >= 1 (chronological index, 0 = oldest bar)",
    "gainLoss": "gain[i] = max(change[i], 0); loss[i] = max(-change[i], 0)",
    "seed": "At index P (P = RsiPeriod): avgGain[P] = (sum of gain[i] for i from 1 to P) / P and avgLoss[P] = (sum of loss[i] for i from 1 to P) / P, i.e. the simple mean of the first P changes",
    "recursion": "For i > P: avgGain[i] = (avgGain[i-1] * (P - 1) + gain[i]) / P; avgLoss[i] likewise (Wilder smoothing)",
    "rsi": "RSI[i] = 100 - 100 / (1 + avgGain[i] / avgLoss[i])",
    "zeroDenominator": "If avgLoss[i] == 0: RSI = 100 when avgGain[i] > 0, RSI = 50 when avgGain[i] == 0 (no price change at all)",
    "warmup": "RSI, avgGain and avgLoss are EMPTY_VALUE for indices 0..P-1; the first RSI value is at index P and needs P + 1 closes",
    "insufficientHistory": "rates_total <= P: every buffer stays empty and OnCalculate returns 0 so the next call recalculates from scratch"
  },
  "pivots": {
    "pivotHigh": "Bar p is a pivot high when high[p] > high[j] for every j in [p-L, p-1] (strictly higher than all L bars on the left) and high[p] >= high[j] for every j in [p+1, p+R] (not exceeded by any of the R bars on the right)",
    "pivotLow": "Bar p is a pivot low when low[p] < low[j] for every j in [p-L, p-1] and low[p] <= low[j] for every j in [p+1, p+R]",
    "tieBreaking": "Strict left, non-strict right. Among equal highs (or lows) inside one right window, the earliest bar becomes the pivot; a later bar with the same value fails the strict left test against it",
    "L": 5,
    "R": 5,
    "history": "A pivot needs p - L >= 0 and is only evaluated once bar p + R is closed",
    "rsiAtPivot": "RSI is read at the pivot bars themselves"
  },
  "pairing": {
    "rule": "Each newly confirmed pivot is compared only with the immediately preceding pivot of the same kind (consecutive pivots). The pair is evaluated only if the distance p2 - p1 is between MinPivotDistance and MaxPivotDistance bars inclusive and RSI is defined at p1 (p1 >= P). A nearer previous pivot that is too close blocks the pair; the code never skips back to an older pivot",
    "minDistanceBars": 5,
    "maxDistanceBars": 60,
    "note": "With L = R = 5 two pivots of the same kind are always at least R + 1 = 6 bars apart, so the minimum distance does not bind at the default settings"
  },
  "divergence": {
    "regularBearish": "Consecutive pivot highs p1 < p2 with high[p2] > high[p1] and RSI[p2] < RSI[p1]",
    "regularBullish": "Consecutive pivot lows p1 < p2 with low[p2] < low[p1] and RSI[p2] > RSI[p1]",
    "hiddenBearish": "Optional (ShowHidden = true): consecutive pivot highs with high[p2] < high[p1] and RSI[p2] > RSI[p1]",
    "hiddenBullish": "Optional (ShowHidden = true): consecutive pivot lows with low[p2] > low[p1] and RSI[p2] < RSI[p1]",
    "comparisons": "All comparisons are strict; equal prices or equal RSI values never produce a divergence",
    "hiddenStatus": "Implemented behind the ShowHidden input (default false) and included in the native MQL versus pandas cross-check; not shown in the article charts"
  },
  "confirmation": {
    "reportedAt": "The confirming bar c = p2 + R. The arrow and the stored pair are written at c; the connecting RSI line between p1 and p2 is drawn at the same moment. Nothing is back-dated to p2 as if it had been known there",
    "closedBarsOnly": "The newest bar in OnCalculate (index rates_total - 1) is treated as still forming and never confirms a pivot, so confirmations use closed bars only (c <= rates_total - 2)",
    "repainting": "Once reported, a detection is not removed or moved while the closed history is unchanged. A history reload (prev_calculated = 0) recalculates everything from the new data",
    "liveRsi": "The RSI value of the newest bar is recalculated on every tick, like a standard RSI"
  },
  "presentation": "Separate window, fixed 0-100 scale. Plots: RSI line; regular bearish line and down arrow; regular bullish line and up arrow; hidden bearish and hidden bullish lines and arrows (empty unless ShowHidden = true). Calculation buffers: average gain, average loss, pivot-high flags, pivot-low flags, first pivot index of high-side and low-side detections",
  "nativeRestrictions": "Native MQL only: no DLL imports, no WebRequest, no order or account functions, no alerts, no chart objects",
  "downloads": {
    "mq5": "downloads/BrokerCheck_RSI_Divergence.mq5 (compiled with MetaEditor64 to .ex5; log kept)",
    "mq4": "downloads/BrokerCheck_RSI_Divergence.mq4 (static review only unless an MT4 compiler exists)",
    "calculationSection": "The MQL5 and MQL4 files share a byte-identical calculation section; the native test harness compiles that exact section"
  },
  "data": {
    "connection": "market-data-connection",
    "terminalPath": "terminal64.exe",
    "symbol": "EURUSD",
    "timeframe": "H1",
    "requestedBars": 5000,
    "minimumBars": 3000,
    "barPolicy": "copy_rates_from_pos start_pos 1: the terminal's current bar is excluded; only closed bars are exported",
    "timestamps": "Bar open times exactly as returned by the terminal (epoch seconds). The offset between the terminal's newest tick time and the capture computer's UTC clock is measured and recorded; charts label times as terminal time with that offset",
    "pointConvention": "Prices in USD per EUR with the terminal's digits/point recorded in data/provenance.json",
    "freshness": "Capture time and newest exported bar are recorded; the export is not a live quote",
    "safety": "Never log in, change credentials, trade, or modify orders. Export requires a connected terminal"
  },
  "crossCheck": {
    "method": "The exact MQL5 calculation section runs inside a native MQL5 harness in the MT5 math tester (portable terminal copy in %TEMP%) and is compared with an independent pandas implementation on the identical data records",
    "rsiTolerance": "1e-9 RSI points (justified in the cross-check)",
    "divergenceMatch": "Exact match of (type, confirming bar time, pivot 1 time, pivot 2 time)",
    "edgeCases": [
      "warm-up and seed value",
      "flat prices (zero average gain and loss)",
      "one-way prices (zero average loss or zero average gain)",
      "equal highs and lows (ties)",
      "insufficient history",
      "appended bar and intra-bar updates (bar-by-bar replay)",
      "repeated tick",
      "ShowHidden off versus on"
    ],
    "harnessSettings": "Real-data run uses ShowHidden = true so hidden detections are verified too; a second run with ShowHidden = false checks the default"
  },
  "chartScenarios": {
    "raster": "1920x1080 PNG, dark theme, logo copied from images/brokercheck-logo.png",
    "overview": "img01_overview.png: the newest 240 exported bars, price with RSI panel and every regular divergence detected (default settings) whose pivots and confirming bar fall inside the window",
    "bearish": "img02_bearish.png: the regular bearish detection with the largest RSI difference between its pivots among detections that have 12 bars before pivot 1 and 24 bars after the confirming bar (selection does not look at what price did afterwards)",
    "bullish": "img03_bullish.png: same rule for regular bullish detections",
    "failed": "img04_failed.png: among regular detections not used in img02/img03, those where price moved beyond the second pivot's extreme in the prior direction within 24 bars after the confirming bar (a higher high after a bearish detection, a lower low after a bullish one); the one with the largest RSI difference is shown. The filter deliberately selects a failure and says nothing about frequency",
    "confirmationLag": "img05_confirmation_lag.png: the most recent regular detection whose pivots are at most 30 bars apart, zoomed so pivot 2 and the confirming bar (pivot 2 + 5 closed bars) are both visible",
    "tally": "Detections may be counted as a description of this sample (window, rules, counts). No win rates, no hit rates, no predictive claims"
  },
  "teachingPoints": [
    "What RSI measures and how the Wilder-smoothed version is calculated, including seed and warm-up",
    "An exact, testable definition of swing pivots and regular divergence",
    "Why a divergence can only be reported R closed bars after the second swing",
    "Real bearish and bullish examples and a real divergence after which price kept going",
    "What the indicator does not do: no prediction, no win rate, no trading"
  ],
  "interpretationLimits": [
    "A divergence is a description of past bars, not a forecast",
    "The sample tally is not a hit rate and was not tested for trading performance",
    "Settings are illustrative defaults, not optimized recommendations",
    "Other RSI implementations may seed or smooth differently; values near the start of history can differ"
  ]
}
