Swing Trading Rules — Tactical Entry and Exit Framework
"Swing trading is not prediction. It is defined risk on intermediate moves inside the primary trend."
Learning Objectives
After reading this chapter, you will be able to:
- Define swing trading vs intraday and long-term investing on NSE/BSE
- Apply the six-factor entry score (≥ 80 for strict ENTER) with regime-aware E4 bands
- Apply Nifty regime overlay (bull/bear/sideways) via NIFTYBEES proxy
- Apply the eight-rule exit checklist (X1–X8), including active vs advisory exits
- Distinguish strict ENTER (backtest / orders) from SETUP+ (universe research list)
- Size positions using R-multiple ≥ 1.0 and portfolio risk limits
- Interpret gross vs net backtest results (slippage + STT + charges)
- Use Stock Verifier Swing Trading, Positions, and Screener as one CFA workflow
Introduction
Swing trading captures moves over 2–40 trading sessions. CFA discipline requires:
- Fundamental hygiene first — screener before chart entry.
- Defined risk — stop and target written before the order.
- Trend alignment — long swings only when intermediate trend supports upside.
- Honest backtests — cost-adjusted, out-of-sample, sufficient trade count.
The live engine is in tools/stock-verifier/includes/SwingTradingRules.php (UI: swing-trading.php).
Data source
| Item | Source | Notes |
|---|---|---|
| Scan / backtest price | Yahoo daily close (2Y default; 5Y for CFA verify) | Same series as indicators |
| Positions “Now” | Yahoo live quote | Exit rules still use daily TA |
| Symbol | SYMBOL.NS, .BO fallback | Same as screener TA |
| 52-week % | Rolling 252-session range from bars | Not quote-summary fields |
| Liquidity (E6) | Avg daily value ≥ ₹8 cr (20 sessions) | |
| Cache TTL | 24h | Refresh daily closes before session |
CFA rule: One OHLCV series for price and indicators. Mixing feeds invalidates the signal.
Core Concepts
Sample portfolio (SwingSamplePortfolio)
| Item | Value |
|---|---|
| Universe | 12 validated Tier-A NSE names (TCS, RELIANCE, BHARTIARTL, …) |
| Universe id | swing_tier_a — use in scanner, strategies, and verify-swing-cfa.php |
| Default verification | Live Yahoo replay on 12-name Tier-A sample book |
| Demo mode | php verify-swing-cfa.php --demo (~40% illustrative NAV sample) |
| Live NAV deploy | 40% NAV sim (cap ₹100k) · gates 35% (cap ₹90k) · bull ×1.80 |
| Current live replay | 23.3% cash-realistic annual (legacy sequential 30.3%) |
| Benchmark alpha | +13.5%/yr vs NIFTYBEES (cash-realistic NAV) |
| Aspirational target | 30–50% — sequential model hits 30%; cash-realistic is below |
Engine parameters — Dynamic EMA Swing (v3.7-cash)
| Parameter | Value | Role |
|---|---|---|
| Engine ID | v3.7-cash | Cash/exposure-aware NAV + decoupled gate deploy |
| Profit target | 3.0R + up to 8% boost | Golden cross / volume surge extends target (max +18%) |
| Effective stop | EMA-21 / EMA-9 / SMA-50 / ATR | Min risk floor 2.75% — avoids churn from ultra-tight EMA |
| Entry E9 | Dynamic momentum gate | Blocks weak momentum; hourly EMA bearish blocks live strict |
| Entry E10 | EMA-21 extension guard | ≤4.5% above EMA-21 unless golden cross / volume surge |
| NAV regime scale | Bull ×1.80 / bear ×0.80 | Walk-forward P&L scaling on top of NAV deploy |
| Gate deploy | 35% / cap ₹90k | Portfolio heat gates — unchanged from v3.5 |
| NAV deploy | 40% / cap ₹100k | Reinvestment sizing (decoupled from gates) |
| Cash/exposure track | nav_exposure_aware | Locks deploy on entry; daily equity curve for DD |
| Live chop guide | isDiscoveryChopRegime() | UI warning; live chop scale ×0.70 (not in backtest) |
| Exit X3 | EMA-21 + weak momentum | Active without waiting for full bear regime |
| Exit X6 | High trail or EMA-9 trail | Trails below daily EMA-9 after 50% of target |
| Exit X9 | Hourly EMA bearish | EMA-9 < EMA-21 with partial gain (live only — not in 5Y daily replay) |
| Breakeven win rate | ~25% gross / ~30% net | 1÷(1+3) + charge buffer |
| Entry score | ≥ 88 bull / 90 sideways | Unchanged strict floor |
| Net edge | Target − 1.25% charges ≥ 4% | Only trades with real 3R payoff |
| Strict liquidity | ≥ ₹12 cr | Unchanged |
Latest CFA Evidence (v3.7-cash)
Cash-realistic NAV (locks deploy while positions are open) is the primary replay metric. The legacy sequential model (assumes full NAV always deployable) is shown for comparison.
| Model | Annual NAV | Max DD | Alpha/yr |
|---|---|---|---|
| Cash-realistic | 23.3% | 7.7% | +13.5% |
| Legacy sequential | 30.3% | 14.0% | +20.5% |
Yearly cash-realistic NAV returns:
| Year | NAV return | Trades exited |
|---|---|---|
| 2022 | +15.3% | 22 |
| 2023 | +31.5% | 32 |
| 2024 | +44.3% | 47 |
| 2025 | −4.0% | 21 |
| 2026 | +10.3% | 15 |
CFA interpretation: exposure tracking reveals the prior 30.3% headline assumed unlimited overlapping deploy. With realistic cash locks, CAGR is 23.3% (still positive alpha, PF 2.35). Peak deploy hit 100% with up to 5 concurrent positions — size new entries only when cash is available.
Formula:
Risk (₹) = Entry − max(hard, structural EMA stop) (floor 2.75%)
Target (₹) = Entry + 3 × Risk (+8% if strong momentum + golden/volume)
Reject ENTER if achieved R < 3.0 after cap
Prior tune — 1:3 R:R Swing (v2.2-3r, reference)
| Parameter | Value | Role |
|---|---|---|
| Engine ID | v2.2-3r | Fixed % stops; target 1:3 reward:risk |
| Profit target | 3.0R | Min +6%, max +18% |
Prior tune — v2.1-cfa (reference)
| Parameter | Value |
|---|---|
| Profit target | 2.0R, min +5%, max +12% |
| Min R | ≥ 2.0 |
| Entry score | ≥ 85 bull / 88 sideways |
Nifty regime overlay (SwingMarketRegime)
Proxy: NIFTYBEES daily chart (Nifty 50 ETF).
| Regime | Detection (summary) | E4 52w band | Exit overlay |
|---|---|---|---|
| Bull | Price ≥ SMA-200, SMA-50 ≥ SMA-200, 20d return > 0 | 25–75% | X3 advisory |
| Bear | Price < SMA-200 or SMA-50 < SMA-200 | 20–55% | X3 active; blocks strict ENTER |
| Sideways | Flat 60d return | 30–65% | X7 active at 12 sessions |
| Neutral | Fallback | 32–68% | Standard exits |
High vol (ATR% ≥ 2.5): entry score −5. Bear regime: entry score −15.
Verdict tiers (v2)
| Verdict | Use | Criteria (summary) |
|---|---|---|
| Strict ENTER | Backtest, live orders | Score ≥ regime floor + E1/E6/E7/E8 + quality + net edge + R ≥ 3.0 |
| Discovery ENTER | Universe scan | Score ≥ 80 + E1 + relaxed PA + E6 |
| SETUP | Research watchlist | Score ≥ 70 + E1 + pullback forming |
| WATCH | Monitor | Score ≥ 70 or 4+ rules + E1 |
Universe filter default: SETUP+ (not strict ENTER only).
Six-factor entry score (0–100)
| Factor | Max pts | Source |
|---|---|---|
| Trend (E1+E7) | 25 | SMA + EMA alignment |
| Momentum (E2+E3+HL) | 20 | Pullback + MACD |
| Volume (E6) | 15 | Avg daily value tiers |
| Price action (E8) | 20 | HL / reversal candle (10 neutral if no bars) |
| Volatility (E4+E5) | 10 | 52w band + not extended |
| Risk (R-multiple) | 10 | R ≥ 1.75 |
Tiers: Strong Buy ≥ 90 · Buy ≥ 80 · Watchlist ≥ 70 · Reject < 70
CFA proficiency audit (v2.0 → v2.1)
| Metric | v2-regime (Nifty 50, 5Y) | v2.1-cfa (same) |
|---|---|---|
| Closed trades | 631 | 222 (−65%) |
| Net win % | 49.4% | 45.5% |
| Profit factor | 1.07 | 1.20 |
| Net compounded | −85% | −15% |
| Net P&L (₹15k/trade) | −₹18,932 | +₹692 |
| Total charges | ₹29,871 | ₹10,410 |
Root cause (CFA): Gross edge was ~symmetric (+3.9% / −3.7%) while fixed CNC charges (~₹47/trade) and X4 scratch exits destroyed net expectancy. Fix: fewer, higher-quality entries (R≥2, net-edge gate, ₹12 cr+ liquidity) and deferred partial exits.
The prior engine used a 7/8 rule count for strict ENTER. v2 keeps the same E1–E8 rules but gates orders on score + mandatory E6/E8 + regime. Backtests without regime data use neutral bands (32–68%).
Entry rules (E1–E8)
| ID | Rule | Criterion |
|---|---|---|
| E1 | Trend | Price ≥ SMA-50 ≥ SMA-200 (200+ bars) |
| E2 | Pullback | RSI 40–56 or within 3% of SMA-50 / EMA-21 |
| E3 | Momentum | MACD histogram ≥ 0 or turning up |
| E4 | 52w band | Regime band (bull 25–75%, bear 20–55%, default 32–68%) |
| E5 | Not extended | RSI < 65, BB %B < 85 |
| E6 | Liquidity | Avg daily value ≥ ₹8 cr |
| E7 | EMA stack | Price ≥ EMA-50 ≥ EMA-200; EMA-9 > EMA-21 > EMA-50 |
| E8 | Price action | Higher low + (HH or bullish reversal / support rejection candle) |
Strict ENTER additionally requires: entry score ≥ 80, E6 liquidity, E8 when OHLC bars exist, R ≥ 1.75, and regime not bear-blocked.
Exit rules (X1–X8)
| ID | Rule | Active? | Criterion |
|---|---|---|---|
| X1 | Stop-loss | Yes | min(−5%, 1.2×ATR%) hard / breakeven active stop |
| X2 | Profit target | Yes | Frozen 1.75R target (min +4%) |
| X3 | Trend break | Bear: active | SMA-50 − 1.5% buffer |
| X4 | RSI exit | Yes | RSI > 65 and gain ≥ 65% of target (min +2.5%) |
| X5 | MACD loss | Advisory | No standalone exit (avoids churn) |
| X6 | Trailing stop | Yes | −2.5% from high after 50% of target progress |
| X7 | Time stop | Sideways: active | ≥ 12 sessions flat (15 advisory otherwise) |
| X8 | Price action | Yes | LH/LL or bearish engulfing and gain ≥ partial threshold |
Exit when any active rule triggers.
Formula & Explanation
Position size
Position size (₹) = (Portfolio × Risk%) ÷ Stop-loss%
Example: ₹10,00,000 portfolio, 1% risk, 4% stop → risk ₹10,000 → max exposure ₹2,50,000.
R-multiple
Risk (₹) = Entry − Effective stop
Target (₹) = Entry + (MIN_R × Risk) MIN_R = 1.75
Target % = clamp(Risk% × 1.75, 4%, 12%) frozen at entry for X2
Effective stop = max(Entry × (1 − min(5%, 1.2×ATR%)), SMA-50 × 0.99, EMA-21 × 0.99) — for R sizing only
Active X1 stop = ATR-aware hard OR breakeven (entry + 0.35%) after 50% of target
Strict ENTER requires R ≥ 1.75 after the target band is applied.
Cost-adjusted backtest
Adjusted entry = Entry × (1 + slippage%)
Adjusted exit = Exit × (1 − slippage%)
Net P&L = Gross − STT − stamp − exchange − GST − DP
Report net win rate and net compounded return — not gross only.
Visual Guide
CFA workflow
[Screener quality preset] → [Swing SETUP+ scan] → [Symbol strict ENTER] → [Positions tracker]
Entry flow (strict ENTER)
[Funda OK?] ──No──► Do not swing
│ Yes
▼
[E1 trend + E7 EMA stack] ──No──► AVOID / WATCH
│ Yes
▼
[Pullback + MACD + 52w band + liquidity] ──No──► WATCH
│ Yes
▼
[E8 price action + score ≥ 80 + R ≥ 1.75] ──No──► WATCH / SETUP
│ Yes
▼
STRICT ENTER
Worked Example — Indian Market
Stock: INFY (illustrative)
| Field | Value |
|---|---|
| Entry | ₹1,520 |
| Stop (−4%) | ₹1,459 |
| Target (+4%) | ₹1,581 |
| R-multiple | (1581−1520) ÷ (1520−1459) = 1.0R |
| E8 | Higher low + hammer at EMA-21 |
Real World Example
Large-cap banks (HDFCBANK, ICICIBANK): Liquid, respect SMA-50; suitable for rule practice.
Mid-cap metals: Wider gaps — same 4% stop may be too tight; reduce size or skip.
Case Study
Strict ENTER backtest (10 Nifty large caps, 2Y, cost-adjusted, v2-regime):
- Run
php benchmark-swing-rules.phpfor a quick 10-name replay (NIFTYBEES regime walk-forward). - Run
php verify-swing-cfa.php --symbols TCS,INFY,...or--universe nifty500 --max 50for CFA verification. - Do not cite win rate without trade count and net returns.
- CFA standard: ≥ 30 trades per regime before trusting win %.
CFA Exam Tip
Examiners reward process: written stop, R-multiple, sample size, and survivorship-free backtests. A high win rate with small average win and large average loss is negative skew — size down.
Common Mistakes
| Mistake | Fix |
|---|---|
| Using SETUP+ as automatic buy | Orders only on strict ENTER |
| Ignoring net P&L after STT | Use Positions charge breakdown |
| Tuning rules to hit 70% win | Freeze rules; validate on Nifty 500 × 5Y |
| Chasing 52w highs | E4 band 32–68% |
| Skipping screener | screener.php?preset=quality first |
Enterprise workflow — picking best swing trades
CFA funnel (quality over quantity)
1. Strategies → Hybrid Quality→Swing (Nifty 100)
2. Sort by swing_rank — trade Tier A (score ≥ 70) only
3. Confirm strict ENTER on symbol page
4. R ≥ 1.75 · target ≥ +4% · liquidity ≥ ₹8 cr
5. Track in Swing Positions with frozen stop/target
Swing rank score (0–100) — v2
| Component | Points |
|---|---|
| Entry score (six-factor) | up to 65 (score × 0.65) |
| Strict ENTER | +25 |
| SETUP | +12 |
| R-multiple OK | +8 |
| Liquidity ≥ ₹8 cr | +6 |
| Bear regime | −8 |
| Stale chart | −10 |
Tier A (≥70): order candidates · Tier B (50–69): watchlist · Tier C: research only
Portfolio heat (SwingPortfolioRisk)
Heat % = Σ (entry − stop) × shares ÷ portfolio NAV
Block new entries when heat ≥ 4% or open positions ≥ 10
Per-trade risk budget = 1% NAV (suggested shares auto-sized)
Performance (engineering)
- Batch cache:
DataCache::getJsonMulti()— one DB round-trip for TA closes on universe scans. - Parallel Yahoo:
prefetchDailyCharts()— curl_multi for cache misses (12-wide batches). - Single TA pass per symbol via
metricsFromBars()(no duplicate fetch). - Request-scoped chart memo on universe scans.
- Background scan: 25+ symbols auto-queue via
SwingScanJob(run-swing-scan-job.php). - Lazy history: symbol page loads
scanHistoryonly on demand (not every page view). - Portfolio backtest:
SwingTradingBacktest::applyPortfolioGates()— max 10 positions, 4% heat on ₹1.5L NAV. - Daily session: Walkthrough 98 — Swing Daily Session.
Key Takeaways
- Eight entry + eight exit rules with price action (E8/X8).
- Strict ENTER for execution; SETUP+ for discovery; swing_rank for prioritization.
- 1.75R target from stop (min +4%, max +12%), breakeven after 50% of target.
- Backtest reports gross and net metrics with slippage.
- Tools:
strategies.php,swing-trading.php,swing-positions.php,verify-swing-cfa.php.
Practice Questions
- Difference between strict ENTER and SETUP?
- List all eight entry rules.
- Which exit rules are advisory only?
- Entry ₹1,000, stop ₹960, target ₹1,040 — calculate R.
- Why report net win rate, not gross?
Answer Key
- ENTER = full quality + PA for orders; SETUP = forming setup for research.
- E1–E8 as in table above.
- X3, X5, X7 — advisory; X1, X2, X4, X6, X8 active (with gain gates on X4/X8).
- Risk ₹40, reward ₹40 → R = 1.0.
- STT, stamp, DP, and slippage can turn gross wins into net losses on small positions.
FAQ
Does live price on Positions match backtest? Backtest uses closes; Positions uses live quote for P&L but daily TA for rules — expect minor divergence intraday.
How to run CFA verification?
cd tools/stock-verifier
php verify-swing-cfa.php --universe nifty500 --max 50 --range 5y
Related Topics
- Position Sizing
- Risk Management Pro
- Tool:
tools/stock-verifier/strategies.php— swing / positional / hybrid filters - Tool:
tools/stock-verifier/swing-trading.php - Tool:
tools/stock-verifier/swing-positions.php - Tool:
tools/stock-verifier/screener.php— fundamental hygiene