Skip to content

Repository files navigation

NQ Strategy B — 5-min Inverse FVG inside 15-min FVG

+$17K net, only $786 max drawdown over 3 years on 1 MNQ futures. Built after the predecessor strategy (nq-atb-bot-archived) was retired for marginal real-world edge. Same data, same fees, same execution layer — 4× the profit, 4× less drawdown.

Long-only ICT-style intraday strategy for NASDAQ futures (NQ / MNQ), running via the Tradovate API. Detects 5-minute Inverse Fair Value Gap (IFVG) retests that occur inside an active 15-minute Bull FVG zone — a multi-timeframe confluence that selects for genuine follow-through, not random breakouts.


Equity Curve — 3 Years (Jan 2023 to May 2026, 1 MNQ)

Strategy B equity curve

Backtest Results

LONG-ONLY (deployed configuration), 1 MNQ baseline:
  Trades:        432 over 3 years (~140/year, ~2-3/week)
  Win Rate:      53.5%
  Profit Factor: ~2.3
  Net P&L:       +$17,187
  Max DD:        $786           ← outstanding risk-adjusted
  Return/DD:     ~22x
  Profitable years: 4/4  (every year positive)
  Profitable quarters: 13/14 (93%)

Comparison vs ATB on identical data

ATB D3 (archived) Strategy B (this bot)
Trades 332 432 (+30%)
Net P&L (1 MNQ) +$8,305 +$17,187 (2.07×)
Max monthly drawdown $5,766 $537 (10.7× less)
Profitable months 21/41 (51%) 35/41 (85%)
2023 P&L -$5,292 +$1,564 (saved -$7K)
Months underwater 35 6

Strategy B was ahead of ATB starting month 1 and never gave up the lead across the full 3-year period.

Year-by-year robustness (long-only)

Year Trades WR PF Net MaxDD
2023 127 46.5% 1.44 +$1,974 $621
2024 139 52.5% 2.24 +$5,430 $610
2025 117 57.3% 2.47 +$6,623 $786
2026 (4mo) 47 68.1% 2.82 +$3,319 $668

Every year profitable. WR improving over time.


How the Strategy Works

Multi-timeframe FVG confluence (long-only):

  15-min timeframe                  5-min timeframe
  ────────────────                  ────────────────
   ┌──────────┐                      ┌──────┐
   │  15m     │  ──→ confluence      │  5m  │
   │  Bull    │      check           │ Bull │
   │  FVG     │                      │ FVG  │
   │  zone    │                      │ zone │
   └──────────┘                      └──────┘
                                          ↑
                                  Price dips into 5m FVG,
                                  closes back above → IFVG retest
                                          ↓
                              ┌─ LONG ENTRY (next bar open) ─┐
                              │  Stop:  5m FVG bottom - 2pts │
                              │  Target: 2 × risk            │
                              │  Exit by: 15:45 ET           │
                              └──────────────────────────────┘

Setup detected when ALL of the following are true:

  1. An active 5-min bull FVG exists (not yet mitigated)
  2. That 5-min FVG sits inside an active 15-min bull FVG zone (with 5-pt buffer at top)
  3. Current 5-min bar's low dips into the 5-min FVG (bottom ≤ low ≤ top)
  4. Current 5-min bar's close is back above the 5-min FVG top
  5. Bar time is between 09:30 and 12:00 ET (entry window)
  6. No position currently open AND day's trade count below cap

Why long-only: Backtest showed shorts are much weaker (42.5% WR vs 56.5% long). NQ has positive drift over time; the symmetry isn't there.

Why this works: FVGs form when one bar's high < bar+2's low (or vice versa) — that's a price inefficiency indicating fast institutional flow. Multi-timeframe confluence requires institutional momentum AND structural setup AND a retest entry — a real edge instead of random breakouts.


Repository Layout

.
├── main.py                          # Async event loop (Schwab stream + Tradovate)
├── config.py                        # Reads .env, exposes typed Cfg
├── requirements.txt
├── pytest.ini
│
├── signals/
│   └── strategy_b.py                # Live Strategy B detector
│                                       - FVGTracker (5m + 15m)
│                                       - FifteenMinAggregator
│                                       - StrategyBDetector → StrategyBSignal
│
├── execution/
│   ├── tradovate.py                 # Auth + REST + WebSocket
│   └── schwab_stream.py             # Real-time 5-min bar feed
│
├── risk/
│   └── manager.py                   # Daily P&L caps, trade-count
│
├── analysis/                        # Reproducible backtests
│   ├── ict_fvg_backtest.py          # The original Strategy B (A/B/C variants)
│   └── smc_breakout_backtest.py     # Underlying simulator helpers
│
├── data/
│   ├── nq_databento_5min.csv        # 3 years of 5-min NQ bars (Databento)
│   ├── vix_daily.csv
│   └── fetch_databento.py
│
├── run_strategy_b_robustness.py     # Year/quarter walk-forward of Strategy B
└── run_atb_vs_strategy_b.py         # Side-by-side vs ATB (same dataset)

Setup

1. Install

git clone https://github.com/prashanthaitha24/nq-strategy-b-bot.git
cd nq-strategy-b-bot
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt

2. Configure

cp .env.example .env
# Edit with your Tradovate credentials
# KEEP TRADOVATE_ENV=demo until you have 30+ days of paper data

3. Verify the backtest claims yourself (recommended first step)

# Reproduces the +$16,468 Strategy B headline number
python analysis/ict_fvg_backtest.py

# Year-by-year + quarter-by-quarter robustness
python run_strategy_b_robustness.py

# Side-by-side Strategy B vs the archived ATB
python run_atb_vs_strategy_b.py

4. Run on demo

python main.py
# Tail logs:  tail -f logs/strategy-b.log

5. After 2+ weeks of stable demo performance

  • Review daily logs — confirm signal cadence matches backtest (~2 trades/week)
  • Confirm fills match backtest entries (real slippage is the unknown)
  • Only THEN consider switching TRADOVATE_ENV=live
  • Start with 1 contract even when going live

Capital Requirements (for live trading later)

Account size Max DD risk Recommended contracts
$5,000 Backtest max $840 → ~17% account hit 1 MNQ
$10,000 Same DD → ~8% account hit 1 MNQ
$25,000+ Comfortable up to 2 MNQ
$50,000+ Could scale to 1 NQ 1 NQ = 10× MNQ exposure

Backtest's $840 max DD over 3 years is exceptional but not a guarantee. Real-world max DD will likely be 2-3× worse due to slippage, missed fills, and regime changes. Plan accordingly.


Realistic Expectations

What backtest says:

  • ~100 trades/year, 56% WR, +$5K/year on 1 MNQ
  • Max DD only $840 over the full period

What real-world will likely produce (haircuts for fills, commissions, edge erosion):

  • 50-55% real WR
  • +$3-4K/year per MNQ
  • Max DD probably $1,500-2,500 in real conditions
  • 1-2 losing months per year

Bad signs to watch for in demo:

  • More than 5 trades/week (likely a bug — backtest is ~2/week)
  • Win rate below 45% over 30+ trades
  • Multiple consecutive stop-outs without trend reversal

Good signs:

  • 1-3 trades/week
  • Most exits are PROFIT_TARGET (the 2× R:R hits)
  • Drawdowns recover within 1-2 weeks
  • 15-min FVG zones are visible in logs before each signal

License

MIT


Disclaimers

  • NOT financial advice. Published for educational purposes.
  • Trading futures involves substantial leverage and risk of total loss.
  • Past performance does not guarantee future results.
  • The author has no financial relationship with Tradovate, Schwab, Databento, or any broker.
  • Demo trade for AT LEAST 30 days before considering live capital.
  • Backtests use 5-min bars as a proxy for 1-min IFVG entry timing. Real 1-min execution may differ.

About

NQ futures bot — 5-min Inverse FVG inside 15-min FVG (long-only ICT confluence). 3-year backtest: +K net on 1 MNQ, only max drawdown, every year profitable. Tradovate + Schwab streaming. Reproduce the numbers yourself.

Topics

Resources

Stars

4 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages