Skip to content

Latest commit

 

History

History
273 lines (207 loc) · 12.2 KB

File metadata and controls

273 lines (207 loc) · 12.2 KB

🇮🇳 IndianMarketBot

A live, always-on trading dashboard + algorithmic SIP / swing / F.I.R.E. engine for the Indian stock market — built for a Euro-resident investor.

Python 3.11+ License: Apache 2.0 Tests: 69 passing UI: Textual DB: DuckDB Daemon: APScheduler

"Earn in Euros, invest in Rupees, watch it from a Pi on the wall."


✨ What's inside

One Python package, three deliverables, one DuckDB file:

                    ┌───────────────────────────┐
                    │ pure strategy core        │
                    │ (no I/O, no Rich, async-  │
                    │  agnostic — fully tested) │
                    └────────────┬──────────────┘
                                 │
        ┌────────────────────────┴───────────────────────┐
        │                                                │
┌───────▼────────┐                            ┌──────────▼──────────┐
│  imbot daemon  │  writes  ┌─────────────┐   │     imbot ui        │
│  (asyncio +    ├─────────►│  state.duck │◄──┤  (Textual TUI;      │
│   APScheduler) │           │     db      │   │  read-only;         │
│                │           └─────────────┘   │  refreshes 2-10s)   │
└────────────────┘             ▲ ▲ ▲          └─────────────────────┘
                               │ │ │
                               │ │ └──── imbot fire / dividend / swing / project
                               │ └────── imbot backtest dividend / swing
                               └──────── imbot optimize --param atr-mult=...

imbot daemon runs cron-style jobs: refresh prices every 5min during NSE hours, scan for swing setups at 15:25 IST, regenerate the dividend list at 16:00 IST, deposit your monthly SIP on the last NSE trading day. imbot ui is a Textual dashboard with live positions, equity curve, bot brain, and event log — read-only DuckDB so it never blocks the daemon.


🚀 Quickstart

# 1. Clone + venv
git clone https://github.com/GhostRoboticsLab/IndianMarketBot.git
cd IndianMarketBot
python3.11 -m venv venv
source venv/bin/activate

# 2. Install (editable, with dev extras)
pip install -e ".[dev]"

# 3. Verify
pytest -q              # 69 tests, ~1s

# 4. Pick your entry point
imbot menu             # interactive picker
imbot fire             # one-shot: monthly F.I.R.E. allocation
imbot daemon           # long-running scheduler (Ctrl+C to stop)
imbot ui               # live dashboard

Three console scripts ship: imbot (CLI), imbot-daemon (long-running scheduler), imbot-ui (Textual app). They all share one DuckDB file at ~/.imbot/state.duckdb (override via IMBOT_HOME=/var/lib/imbot).


🧠 The strategy

Three F.I.R.E. routes, four bots, one regime-aware engine. Documented in Docs/FIRE_Strategies_40k_SIP.md.

Route Style Vehicle Wins when
1. Snowball 🐌 Income High-yield stocks + DRIP Retirement — live off dividends
2. Indexing 📚 Reliability Nifty 50 / Next 50 ETFs Always (given 15-year horizon)
3. Momentum 🚀 Alpha Mid/Small caps, 200-DMA + 6M momo Bull markets

The daemon rebalances dynamically based on Nifty 50's 200-DMA:

   BULL (Nifty > 200-DMA)               BEAR (Nifty < 200-DMA)
   ┌────────────────────┐               ┌────────────────────┐
   │ Core ETFs    40% ████░░░░░░░░░░░   │ Core ETFs    80% ████████████████░░
   │ Alpha picks  60% ████████████░░░   │ Alpha picks  20% ████░░░░░░░░░░░░░░
   └────────────────────┘               └────────────────────┘

The V4.0 "institutional math" stack running inside the daemon:

  • ATR-based 1%-risk sizing — every position risks exactly 1% of equity if stopped out
  • Relative Strength filter — only buy stocks outperforming Nifty's 20-DMA-of-RS
  • Market breadth gate — refuse new entries unless >40% of universe is above 50-DMA
  • Chandelier trailing stopClose − 2.5 × ATR, lets winners run
  • Hard time-stop — any position held ≥20 days exits, win or lose (fixes runaway-winners-stuck-open bug in the legacy bot)

🧰 CLI cheatsheet

# screening / allocation (live, one-shot)
imbot fire --budget 500
imbot dividend --budget 10000
imbot swing --top 5 --rr 2.5

# forward projection (pure math, no network)
imbot project --years 15 --sip 500 --expense 2500

# backtests (downloads history)
imbot backtest dividend --years 5 --sip 500
imbot backtest swing --years 2 --capital 1000000

# parameter grid search
imbot optimize --list
imbot optimize --param atr-mult=2.0,3.0,0.25 --param time-stop=15,30,5

# daemon + dashboard
imbot daemon                 # foreground; for systemd see Docs/operations.md
imbot ui                     # Textual dashboard

# DuckDB helpers
imbot db init
imbot db inspect
imbot db migrate-json legacy/virtual_account_state.json

🛰️ Daemon jobs

 health_beat        every 30 s         (heartbeat row)
 paper_tick         every 60 s, NSE    (trailing stops + exits)
 prices_tick        every 5 min, NSE   (OHLCV cache refresh)
 signals_swing      daily 15:25 IST    (V4.0 swing setups)
 paper_eod          daily 15:25 IST    (new entries if regime + breadth bull)
 signals_dividend   daily 16:00 IST    (snowball candidates)
 signals_fire       daily 16:30 IST    (FIRE allocation incl. regime)
 monthly_sip        09:30 IST · last NSE day of month (deposits EUR→INR)

Each job hits Yahoo Finance through data.yahoo.fetch_*_async — 10s timeout, 3 retries, exponential backoff. NSE-hours gated via @requires_market_open so decisions never run at 2am on stale data.


🔧 Tweaking

Knobs you might actually want to turn live in config/default.toml. Override via:

  1. ~/.imbot/config.toml (per-user file, same TOML layout)
  2. IMBOT_* env vars: IMBOT_RISK__MAX_POSITIONS=5, IMBOT_SIP__AMOUNT_EUR=750
To change... Edit...
Tradable universe src/indianmarket/universe.py
Risk per trade / max positions / ATR multiplier config.risk
Monthly SIP amount / deposit time config.sip
Daemon cadence config.daemon
NSE holidays src/indianmarket/data/market_calendar.py
FX fallbacks config.fx
Bull/bear allocation split config.allocation

The strategy core is fully pure — change a function in src/indianmarket/core/*.py and your update flows through the CLI, daemon, and dashboard with no extra wiring.


📁 Repository layout

IndianMarketBot/
├── pyproject.toml              # deps, console_scripts (imbot, imbot-daemon, imbot-ui)
├── config/
│   └── default.toml            # canonical knobs (override via ~/.imbot or env)
├── src/indianmarket/
│   ├── config.py               # TOML + env var loader
│   ├── universe.py             # one source of truth for ticker lists
│   ├── constants.py            # risk + execution defaults
│   ├── core/                   # pure strategy: indicators, regime, sizing,
│   │                           # momentum, dividend, swing, projection, backtest
│   │                           # — 100% I/O-free, fully unit-tested
│   ├── data/
│   │   ├── yahoo.py            # the ONLY module that imports yfinance
│   │   ├── cache.py            # in-memory TTL cache
│   │   ├── store.py            # DuckDB read/write + JSON migration
│   │   ├── schema.sql          # prices / signals / positions / trades / ...
│   │   └── market_calendar.py  # NSE hours + holidays + @requires_market_open
│   ├── daemon/                 # asyncio event loop + APScheduler jobs
│   │   ├── runner.py           # SIGTERM/SIGINT graceful shutdown
│   │   ├── scheduler.py        # cron triggers
│   │   └── jobs/               # prices, paper_trader, signals_*, monthly_sip
│   ├── ui/                     # Textual TUI (read-only DuckDB)
│   │   ├── app.py              # 3×2 grid layout
│   │   └── widgets/            # header, positions, signals, brain, log,
│   │                           # equity chart (textual-plotext), status bar
│   ├── cli/                    # Typer subcommands
│   │   └── commands/           # fire, dividend, swing, project, backtest,
│   │                           # optimize, daemon, ui, menu, db
│   ├── optimize/grid_search.py # cartesian-product param sweeps
│   └── tests/                  # 69 unit + smoke tests (pytest)
├── Docs/
│   ├── FIRE_Strategies_40k_SIP.md
│   └── development_journey.md
├── CLAUDE.md                   # guidance for Claude Code agents
└── LICENSE                     # Apache 2.0

🥧 Running on a Raspberry Pi

# On the Pi
sudo apt install -y python3.11-venv git
git clone https://github.com/GhostRoboticsLab/IndianMarketBot.git ~/imbot
cd ~/imbot && python3.11 -m venv venv && source venv/bin/activate
pip install -e .

# systemd: start daemon at boot
sudo cp scripts/imbot.service /etc/systemd/system/    # see Docs/operations.md (C15)
systemctl --user enable --now imbot

# From the Pi's HDMI-attached monitor (or SSH session)
imbot ui          # full-screen Textual dashboard

The UI auto-falls-back to an ASCII sparkline if textual-plotext doesn't render correctly on the Pi terminal. Layout collapses to single-column below ~100 cols.


⚠️ Disclaimer

This is research/educational code, not financial advice.

  • The bots produce signals. They do not place real orders. Execution is on you.
  • paper_trader is virtual money only — no broker API is wired in.
  • yfinance data can be delayed or wrong. Never trust a screen blindly.
  • Past backtest performance does not predict future returns.
  • Universe lists were curated knowing what works today → survivorship bias is real in the backtests.
  • The author is not a SEBI-registered investment advisor.

By using this code you accept full responsibility for any decisions made with it.


🛠️ Built with


📜 License

Apache 2.0 — do what you want, just don't sue me.

Star ⭐ this repo if it sparked an idea. PRs welcome.