# Do W.D. Gann's time rules work on the Nifty? A 2007–2026 backtest

> Four of five Gann time rules fail on the Nifty; only 'exceeding previous moves in time' survives.

Published 2026-10-19 by TRINETRA.


**Run:** 2026-10-19 · `engine/scripts/bench_gann_time.py` · raw JSON `BENCH_gann_time.json`
**Universe:** NIFTY 50 (`^NSEI`) daily, **4,683 bars, 2007-09-17 → 2026-10-19 (20 calendar years)**
**Pivots:** 217 "important" swings (10-bar fractal, ≥3% alternating swing filter)
**Horizon:** 20 trading days · **Tolerance:** ±3 calendar days

---

## TL;DR

| Rule | Verdict |
|---|---|
| R1 Gann's solar-seasonal date map | ❌ **NO EDGE** (lift 1.12, p=0.15) |
| R2 Anniversary dates (1-5y from pivots) | ❌ **NO EDGE** (lift 1.04, p=0.35) |
| R3 Fractional-year divisions (13/17/26/35/39w) | ❌ **NO EDGE** (lift 1.06, p=0.23) |
| R4 Degree day-counts (30…360d from pivots) | ❌ **NO EDGE** (lift 1.03, p=0.35) |
| **R5 Exceeding moves in TIME** | ✅ **SIGNAL — robust, +2.6% edge, 84% win** |
| R6 India-empirical seasonality | ✅ **Strong month effects — but NOT Gann's dates** |

**Four of Gann's five time constructs are statistically indistinguishable from noise on
Indian equities. The fifth — the one Hima Reddy ranks FIRST and which contains no astrology,
no geometry and no free parameters — is a real and unusually strong signal.**

---

## 1. The date-cycle rules fail — and the coverage column shows why

This is the "skeptic's ledger #1" hazard measured directly
(`docs/trading-library/notes/11-gann-master-stock-market-course.md`).

| Rule | Coverage of all trading days | Base pivot rate | Rate on predicted days | Lift | p |
|---|---|---|---|---|---|
| R1 solar map | 34.9% | 4.63% | 5.20% | 1.121 | 0.153 |
| R2 anniversary | 59.2% | 4.63% | 4.80% | 1.036 | 0.351 |
| R3 fractional year | 69.0% | 4.63% | 4.92% | 1.062 | 0.231 |
| R4 degree days | **92.2%** | 4.63% | 4.77% | 1.029 | 0.345 |

**R4 "predicts" 92.2% of all trading days.** A rule that fires on nine days in ten is not a
forecast. This is precisely the failure mode the notes predicted: the union of Gann's many
cycles, each with a tolerance, covers essentially the whole calendar, so *recall* looks
spectacular while *precision* is nil.

Had this been measured the usual way — "what % of major turns landed near a Gann date?" — R4
would have scored **~92% and been reported as a triumph.** It is the control that kills it.

**R1 deserves a specific note** because it is Gann's most-quoted contribution. Lift 1.12 is
directionally positive but **p=0.15 is not significant** on 20 years. Mechanistically this is
expected: Gann's own stated reason for the January date is *US* dividend convention
("Dividends are paid on the first of January, and people buy for the dividends"), and his
map is anchored to the US fiscal calendar. India's FY ends 31 March. The notes predicted
this would not transfer; it does not.

---

## 2. R5 — "Exceeding moves in time" — the real finding

**Gann Buying Point #4/#5, Selling Point #4/#6.** Reddy ranks this *first* in importance.

> "BUY when the first rally from the extreme bottom **exceeds in time** the greatest rally in
> the preceding Bear Campaign."

| signal | n | avg 20d fwd | control (all bars) | **edge** | directional win |
|---|---|---|---|---|---|
| **buy** (after bear campaign) | 25 | **+3.46%** | +0.82% | **+2.64%** | **84.0%** |
| sell (after bull campaign) | 15 | −5.32% | +0.82% | +6.14% | 53.3% |

### Robustness — this is what makes it credible

**(a) Parameter sensitivity: 24/24 configurations positive.**
Swept `PIVOT_WIN ∈ {5,8,10,12,15,20}` × `MIN_SWING_PCT ∈ {2,3,5,8}`:

- **every one of 24 configs showed a positive edge**
- min +1.97%, median **+3.36%**, max +10.07%
- win-rate 53.8%–95.2%

A parameter-fitted artifact does not survive that. The signal is in the data, not the knobs.

**(b) NOT a "buy the dip" proxy.**
Signals fire at a **median of just −0.94% below the trailing 60-day high** — i.e. near highs,
not after crashes. The matched control (any bar at least that far off its 60d high) returns
**+0.66%**, versus the signal's **+3.46%**. So the edge is not drawdown-reversion.

**(c) NOT one lucky regime.**
Signals occur in **12 distinct years** (2009, 2012, 2013, 2014, 2016×6, 2017, 2018, 2019,
2021, 2022, 2023, 2025); max 6 in any single year.
**Excluding 2008/09 (GFC) and 2020 (Covid): n=23, +2.85%, 82.6% win.**

### Why it plausibly works (mechanism, not numerology)
Duration asymmetry is a *structural* statement about supply exhaustion: if the first
counter-rally lasts longer than any rally during the whole preceding decline, the character of
participation has changed — sellers are no longer able to cap advances on their old schedule.
That is a regime statement, and it needs no cycles or planets.

### The honest caveats
1. **n=25 is small.** The per-config n ranges 9-60; the edge is stable but the sample is thin.
   Treat the magnitude as uncertain even though the sign is robust.
2. **It is a TREND-CHANGE detector, not an entry.** Gann says so himself: after it fires, the
   instrument is "a safer buy **on a secondary reaction**." The correct engine use is a
   *regime/stage input feeding a pullback entry*, never a standalone trigger.
3. **Index-level only so far.** Tested on NIFTY. Per-stock behaviour is unmeasured.
4. **The sell side is weak** — 53.3% directional win is near coin-flip despite the large mean,
   i.e. driven by a few big declines. **Do not trade the short side on this.**

---

## 3. R6 — India's OWN seasonality (derived, not imported)

Control: unconditional 20d forward return **+0.823%**.

| Month | n | avg 20d | edge | win |
|---|---|---|---|---|
| Jan | 396 | −0.90% | **−1.72%** | 38.4% |
| **Feb** | 374 | −1.24% | **−2.06%** | 46.3% |
| **Mar** | 381 | **+2.71%** | **+1.89%** | **70.3%** |
| Apr | 358 | +1.22% | +0.40% | 57.3% |
| May | 397 | +1.85% | +1.02% | 66.2% |
| Jun | 402 | +1.70% | +0.88% | **76.4%** |
| Jul | 418 | +0.91% | +0.09% | 62.2% |
| Aug | 392 | +1.26% | +0.44% | 66.1% |
| Sep | 393 | +0.10% | −0.73% | 58.0% |
| Oct | 378 | +0.43% | −0.39% | 54.8% |
| Nov | 373 | +1.18% | +0.36% | 61.4% |
| Dec | 401 | +0.63% | −0.19% | 58.6% |

### India-specific windows

| Window | n | avg 20d | edge | win |
|---|---|---|---|---|
| Budget (Feb 1 ±10d) | 150 | −1.06% | **−1.88%** | 48.7% |
| Monsoon (Jun-Sep) | 1605 | +1.00% | +0.17% | 65.7% |
| Festive (Sep 15-Nov 15) | 773 | +0.45% | −0.37% | 57.7% |
| **FY-end (March)** | 381 | **+2.71%** | **+1.89%** | **70.3%** |
| FY-start (April) | 358 | +1.22% | +0.40% | 57.3% |
| Advance-tax weeks | 479 | +1.09% | +0.26% | 66.8% |

**The two real effects are Indian, structural, and absent from Gann's map:**
- **March (FY-end) is the strongest month: +1.89% edge, 70.3% win.** Gann's map has *nothing*
  on March 31; his nearest date is the March 21 equinox, for an unrelated reason.
- **Jan-Feb is the weakest stretch (−1.72%, −2.06%)** — the opposite of Gann's "January rise."
  His January claim is explicitly US-dividend-driven and **inverts** on Indian data.
- **The Budget window is negative (−1.88%)**, consistent with event-risk de-grossing.

⚠️ **Caveat on R6:** these are overlapping 20-day forward windows, so observations within a
month are not independent — the effective n per month is far below the nominal ~390, and the
confidence intervals are correspondingly wide. Month-of-year effects are also the classic
home of data-mined "anomalies." Treat R6 as **context for the narrative, not a trade trigger.**
It is reported because it is the honest, India-derived replacement for a US map that failed —
not because 12 monthly means constitute a strategy.

---

## 4. Decisions taken from this run

| Finding | Decision |
|---|---|
| R1-R4 (all Gann date cycles) | **REJECTED.** Will not enter the decision path. Recorded as a negative result; the "Astro/Time" UI section reports them as *measured and failed*, which is more useful to the user than a mystical overlay |
| **R5 buy side** | **IMPLEMENT behind a default-OFF flag** (`gann_time_v1`) as a *regime/stage* input, not a trigger. Promotion gate below |
| R5 sell side | **REJECTED** for trading (53% win). May be surfaced as a caution flag only |
| R6 March / Jan-Feb / Budget | **SURFACE as narrative context** in the macro section with explicit n and the overlapping-window caveat. Not a gate |
| Square of Nine / Hexagon / planetary | **NOT IMPLEMENTED** — underdetermined in the source (notes ledger #4). Implementing would mean inventing the missing half and attributing it to Gann |

### Promotion gate for `gann_time_v1`
Flip ON only when **all** hold:
1. Per-stock (not just index) replay over ≥3 years shows a positive edge on ≥2 regimes.
2. The signal adds information **beyond** our existing Stage/trend gate — i.e. measured on
   names the current ladder would have rated differently (no double-counting).
3. n ≥ 100 signals in the per-stock replay.
4. 4-week shadow A/B on live picks shows no regression in avg R.

---

## 5. Reproduce

```bash
.venv/Scripts/python.exe -I engine/scripts/bench_gann_time.py
```

Data: `data/audit/nifty_ohlc_max.csv` (4,683 bars; fetched from Yahoo `^NSEI` in 2-year
chunks — note NIFTY history on that endpoint starts 2007-09, not 1996).

**Pre-registration note:** R1-R6 and all constants (`PIVOT_WIN=10`, `TOL_DAYS=3`, `FWD=20`,
`MIN_SWING_PCT=3.0`) were fixed in the script's docstring *before* the first run. The
sensitivity sweep was run *after*, to test robustness of the one surviving rule — not to
select it.

---

## 🔴 RETRACTION — 2026-10-20: R5 is NOT a signal

**The R5 verdict above ("SIGNAL — robust, +2.6% edge, 84% win") is withdrawn.**

The per-stock test this report asked for in §2 ("Index-level only — per-stock behaviour is
unmeasured") was run on **678 NSE symbols with ≥1,500 bars**. It shows the edge is a
**selection artifact of the rule's own construction**, not a forecast:

| control | median edge |
|---|---|
| Real series | +6.064% |
| **Own returns SHUFFLED** (same distribution, structure destroyed) | **+6.632%** |
| **Genuine edge** | **−0.568%** |

A rule that scores as well on shuffled data as on real data has found nothing.

**Mechanism:** the signal fires at the **80.8th percentile of its trailing 60-bar range** — near
local highs, right after the longest rally of the campaign. On any positively-compounding series,
conditioning on "a long rally just happened" selects points whose forward path inherits the drift.

**A second defect, which also affected this report:** `find_pivots` cannot identify a pivot at
index `i` until bar `i+PIVOT_WIN`, but R5 fired at `s + t_max + 1` — before the anchoring swing
low was knowable. On pure random walks the unguarded rule returned **+2.070%** over control.

### Why the six controls in this report were not enough
24/24 parameter settings, not-a-buy-the-dip, 12 distinct years, excluding 2008/09 and 2020 — every
one asks *"is the result stable?"* **A mechanical selection artifact is perfectly stable.** The
missing control was the cheap one: *does the rule also "work" on data with no structure?*

**New standard: any future time-based rule must clear a shuffled-series null before being
reported as a signal.** Stability ≠ significance.

### What still stands in this report
- **R1–R4 rejections** (solar map p=0.15; anniversary/fractional/degree cycles, up to 92.2%
  coverage) — unaffected and now better supported.
- **R6 India seasonality** — unaffected. It is a *calendar partition*, not a path-dependent
  rule, so there is no selection mechanism available to manufacture a false edge. Still
  context-only, with its overlapping-window caveat.
- The coverage/precision methodology — unaffected, and it is what caught R1–R4.

Full analysis: `data/research/BENCH_gann_perstock_2026-10-20.md`


_TRINETRA is a research and education tool. Nothing on this site is investment advice or a recommendation to buy or sell any security. Markets carry risk; do your own research and consult a SEBI-registered adviser before investing._
