\"\"\" backtest_regime_aligned_bearish.py (27-Aug-2026) ================================================================ MAKSAD: Item-1 (compute_decision_engine_v2() ka RegimeAligned bug/design- question) ko EMPIRICALLY test karna — theory sirf \"bull/be
Script ka overall structure, objective aur logic broadly coherent hai, aur jo MAKSAD aapne comments mein likha hai (NIFTY caution‑regime ko bearish trades ke context mein empirically test karna) usse kaafi had tak align karta hai. Neeche key points aur potential issues/suggestions:
---
1. Overall flow vs stated MAKSAD
- Events definition:
- Code ab daily 20‑day Donchian breakdown use kar raha hai:
`window_low20 = lows_arr[i - _DONCHIAN_WINDOW:i].min()` with `_DONCHIAN_WINDOW = 20`,
event jab `this_close < window_low20`.
- Top wali docstring / MAKSAD block abhi bhi “weekly‑close, 20‑weeks low” likh rahi hai.
- Conceptually aapka v‑FIX comment theek hai (Turtle System‑1 = 20‑day, daily), lekin header‑comment outdated ho chuka hai. Isse future‑me confusion hoga (“main weekly test samajh ke result interpret kar raha hoon, code actually daily hai”).
- Suggestion: Top docstring ko explicitly update karo:
- “20‑day Donchian breakdown (daily data), Turtle System‑1 style”
- “Weekly‑based proxy ko abandon kiya gaya; reasoning: performance + established convention.”
- Regime classification:
- `_nifty_regime_on_day` ka formula ADX + 50‑DMA slope exactly wahi structure follow karta hai jo aapne describe kiya:
- `adx > 20` & slope > 0 → bullish
- `adx > 20` & slope < 0 → caution
- else → neutral
- `nifty_df_window` 600‑day bounded window se ban raha hai, aur minimum 71 candles enforce ho rahe hain → ADX + 50DMA slope ke liye logically sufficient.
- Grouping & tests:
- Events ko `regime == "caution"` vs `regime != "caution"` mein split karke 10 / 20‑day forward returns compare kiye ja rahe hain.
- Z‑test + permutation test dono compute ho rahe hain → parametric + non‑parametric dono coverage, which is methodologically sound for fat‑tailed returns.
Net: High‑level research question ka implementation correct direction mein hai.
---
2. Code‑level correctness issues / edge cases
1. NIFTY ticker & history fetch
- `nifty_ticker = yf.Ticker("^NSEI")` + `sa._fetch_split_adjusted_history(..., period="max")`
- Agar aapka internal `calculate_adx()` already isi data shape ke saath kaam karta hai to yeh consistent hai.
- `len(nifty_df) < 300` par abort, which is reasonable.
2. Symbol universe & fetch
- Ab universe hard‑coded NIFTY‑50 hai → illiquid / obscure names ka earlier bias remove ho gaya.
- `_SYMBOL_RENAME_OVERRIDES`, `_BSE_ONLY_SYMBOLS`, `_KNOWN_INVALID_SYMBOLS` yahan mostly redundant hain kyunki NIFTY‑50 mein yeh symbols nahi, lekin harmless bhi hain.
- `_fetch_symbol_df` 300+ rows condition lagata hai; daily Donchian+fwd returns ke liye yeh conservative‑but‑fine threshold hai.
3. Donchian event loop
- Loop: `for i in range(_DONCHIAN_WINDOW, n - max_fwd)`
- With `_DONCHIAN_WINDOW = 20` aur `max_fwd = 20`, first valid `i=20` pe 20‑bar low fully defined hai, last `i = n - 21`. Correct.
- Length guard: `if len(df) < 25: ... continue`
- Strictly speaking, pehla non‑empty event ke liye aapko at least 40 bars chahiye (20 back + 20 forward). 25 par file skip nahi ho rahi, bas “no events” natural outcome hai.
- Clarity ke liye isko 40 kar dena better hai, taaki intent and maths align kare.
4. NIFTY regime alignment per event
- `nifty_idx = nifty_df.index.get_indexer([event_date], method="nearest")[0]`
- Nearest‑trading‑day mapping logically sahi hai (individual symbol ki breakdown date ko nearest NIFTY trading day se align karna).
- `_MAX_LOOKBACK_WINDOW = 600` se performance‑safe bounded window banta hai; ADX+50DMA ke liye zyada than enough.
5. COVID‑window handling
- `edf["date"]` ko use karke tz detect karke `covid_start` / `covid_end` construct karna (tz‑aware vs tz‑naive conflict avoid) technical point of view se sahi hai.
- Filter: `2020-01-20` se `2020-11-30` tak ke events drop ho rahe hain, aur ex‑COVID par same comparison run ho raha hai.
- Robustness‑check ka code branch logically consistent hai (agar remaining events > 20).
6. Statistics implementation
- `two_sample_z_test`:
- `ddof=1` sample var, pooled SE correctly compute ho raha.
- `se == 0` edge case handle.
- `permutation_test`:
- Pooled sample, labels shuffle, diff of means compute, exact two‑sided p‑value (`2 * min(p_le, 1 - p_le)`), cap at 1.0. Correct.
- Logging clearly bata raha hai n, mean returns, diff, p‑values.
---
3. Interpretation / output clarity
1. Sign of “Farak”
- Aap `diff = mean_caution - mean_non_caution` le rahe ho.
- Bearish‑trade perspective se “better” = more negative average return (zyada down‑move).
- Practical interpretation:
- `diff < 0` → caution‑events ka avg return non‑caution se zyada negative (good for shorts).
- `diff > 0` → caution less negative / more positive (worse for shorts).
- Suggestion: Log line mein explicitly ek phrase add karo, e.g.:
- `"Farak (CAUTION - NON-CAUTION): {diff:.2f}pp [negative = caution more bearish]"`
Taaki result dekhte hi direction ka confusion na rahe.
2. Regime bucket choice
- Aap NON‑CAUTION = (bullish + neutral) dono club kar rahe ho. YEH ok hai as a primary test, lekin trade‑theory point of view se:
- “caution vs bullish only” aur “caution vs neutral only” alag‑alag dekhna kabhi useful ho sakta hai (agar neutral regime behaviour bilkul alag ho).
- Agar future mein robustness aur detail chahiye ho, toh additional compares add kar sakte ho:
- caution vs bullish
- caution vs (bullish+neutral) [aaj ka code]
- caution vs neutral
3. Survivorship bias
- Current NIFTY‑50 list se pure history backtest ho raha hai → survivorship bias structural hai (jo stocks aaj NIFTY‑50 mein hain, woh historically under‑performers / delisted names exclude karte hain).
- Ye quantitative effect ko distort kar sakta hai, but MAKSAD yahan regime‑alignment directionally test karna hai — conceptually regime effect phir bhi visible ho sakta hai.
- Documentation mein ek do line explicitly add karna worth hai: “Universe = current NIFTY‑50 (survivorship bias present).”
4. Dependence / overlapping windows
- 10/20 daily forward returns heavily overlapping honge; isse individual events independent nahi rehte; isliye classical p‑values nominally “over‑stated significance” de sakte hain.
- Aapne permutation‑test add kiya hai, jo labels shuffle karke dependence ko partly respect karta hai (kyunki pooled series same structure carry karti hai). Phir bhi documentation mein ek line likhna acha hai:
- “Events/returns overlapping hain, isliye p‑values ko rough guide maana gaya hai, not strict hypothesis‑test.”
---
4. Practical/small suggestions
- Top docstring sync with final logic (20‑day daily Donchian, not weekly 20‑week).
- Length guard: `if len(df) < 40:` kar dena, taaki ek bhi event mathematically possible ho.
- Additional small logs:
- Z‑test/permutation ke sath ek hi line: `"Farak negative => caution more bearish (short ke liye better)"`.
- Agar koi regime bucket me events significantly kam hon (e.g., caution events < 20) toh ek warning log line add karna (low statistical power mention).
Functionally, code run‑able, coherent aur research‑question aligned lag raha hai. Major logical flaws nahi dikh rahe; mainly documentation‑sync, minor thresholds, aur interpretation‑clarity ke improvements hain.
If you have any further queries, please connect with us on 022-6290-10141 (Timings : 09.00 AM to 05.00 PM) or you can email us on info@cniinfoxchange.com