Skip to content

Latest commit

 

History

History
80 lines (57 loc) · 4.3 KB

File metadata and controls

80 lines (57 loc) · 4.3 KB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Setup & run

python3.11 -m venv venv && source venv/bin/activate
pip install -e ".[dev]"
pytest -q                      # 69 tests, ~1s

Three console scripts ship:

  • imbot — Typer CLI (imbot fire, imbot backtest swing, imbot ui, imbot menu, etc.)
  • imbot-daemon — long-running asyncio scheduler
  • imbot-ui — Textual dashboard

State lives in a single DuckDB file at ~/.imbot/state.duckdb (override via IMBOT_HOME).

Architecture

core/              pure strategy library (no I/O, no Rich, no yfinance)
data/              the only place that touches yfinance + DuckDB
daemon/            asyncio + APScheduler + 8 cron jobs
ui/                Textual TUI, read-only DuckDB, refreshes every 2-10s
cli/commands/      Typer subcommands — presentation + I/O only
optimize/          cartesian-product param sweeps over SwingBacktestConfig

The contract is: core/ must be importable without side effects, no print, no yfinance, no rich. A future pre-commit hook should enforce this (planned in C15).

Data layer

  • data/yahoo.py — the only yfinance importer. Sync + async wrappers, 10s timeout, 3 retries with exponential backoff. Fault-injection via IMBOT_YAHOO_FAULT_INJECT=hang|raise.
  • data/store.py — DuckDB writer (threading.Lock + asyncio.Lock) + read-only opener (DuckDB MVCC makes parallel reads cheap). Schema bootstrap is idempotent.
  • data/market_calendar.py — NSE 09:15–15:30 IST + holiday set. @requires_market_open decorator gates every decision-making daemon job.
  • data/cache.py — in-memory TTL cache for sync callers; the DuckDB prices table is the persistent cache.

Daemon

imbot daemon runs APScheduler.AsyncIOScheduler with 8 jobs (see README "Daemon jobs" table). Single asyncio process. SIGTERM/SIGINT gracefully stops the scheduler, waits 5s, writes a "daemon stopping" event, exits 0.

Seven legacy bugs are fixed in the daemon:

  1. Monthly SIP refill (no more underinvestment drift)
  2. NSE-hours gating on decisions (legacy gated display only)
  3. Atomic writes (DuckDB transactions replace JSON file)
  4. yfinance timeouts (UI no longer freezes on Yahoo lag)
  5. Time-stop fires on winners too (no more runaway positions stuck open)
  6. atr_at_entry NOT NULL (no silent skipping of trailing-stop updates)
  7. Retry/backoff on transient Yahoo failures

UI

imbot ui opens a Textual app with 6 widgets in a 3×2 grid. Read-only DuckDB connection per query. textual-plotext for the equity chart with sparkline fallback.

The daemon and UI are intentionally separate processes sharing one DuckDB file (DuckDB MVCC allows unlimited concurrent readers against a single writer). A TUI crash never kills the daemon.

Config

config/default.toml is the source of truth. Override via:

  1. ~/.imbot/config.toml (same TOML schema)
  2. IMBOT_* env vars with double-underscore for nested keys: IMBOT_RISK__MAX_POSITIONS=5

Universes (which tickers each bot scans) live in src/indianmarket/universe.py — a single source of truth that replaces the 5 duplicated lists in the old code.

Testing

  • 69 tests at src/indianmarket/tests/
  • Tests use IMBOT_HOME override + tmp_path to isolate per-test DuckDB files
  • One golden value (test_rsi_golden_value) pins indicator semantics — bump intentionally if changed

Things to know before editing

  • core/ purity. Adding print / import rich / import yfinance to anything under core/ will eventually break the daemon (which expects pure functions) and the tests (which run without network). Hold the line.
  • DuckDB writer lock. Never await while holding a write connection — it serializes the whole daemon. Keep transactions small.
  • yfinance is flaky. data.yahoo returns None on terminal failure; callers must handle it. Don't "improve" by raising — silent degradation is intentional.
  • NSE holidays expire. The hardcoded list in market_calendar.py covers 2024-2026; extend yearly.
  • Survivorship bias in universe.py ticker lists is a known limitation, deliberately not fixed in v1 (needs point-in-time index membership data).
  • No broker integration. Bots emit signals; execution is the user's job. Future broker module reads from the signals table.