Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Docs for the development version; the latest release is v0.8.1.

Architecture

Source Layout

src/
  main.rs            CLI definition (clap): 76 top-level commands, the grouped `--help` table, parse tests
  commands/          Command handlers — one file per area, each `cmd_*` re-exported
    mod.rs           Shared imports and helpers (period → interval, symbol resolution)
    overview.rs      quote, markets, dashboard, search, doctor
    setup.rs         config path/show/init
    fundamentals.rs  analyze, compare, peers, dividends, insider, deep, score (`fundamental score`)
    research.rs      events, insights, verdict (printing; the data is in `research.rs`, `events.rs`, `verdict.rs`)
    technicals.rs    technical, history, chart, timeframes, patterns, support, fibs, volume, gaps, stoploss
    risk.rs          risk, correlate, returns, forecast, options moves
    funds.rs         mf search, nav, history, sip, screen, overlap (TER in nav/history/screen)
    fno.rs           options chain, pcr, maxpain, oi, payoff
    commodities.rs   commodity spot, futures, etfs, sgb
    bonds.rs         bonds yields, list, calc
    markets.rs       movers, sectors, news, sentiment, screen, picks, earnings, rotation, matrix, surprise, heatmap, sectorcmp
    ipo.rs           ipo (live board, one issue's analysis)
    calendar.rs      calendar (results, dividends and splits for holdings and watchlist)
    backtests.rs     backtest (single, portfolio, walkforward, strategies)
    strategies.rs    sip, whatif, intraday, longterm, report
    portfolio.rs     portfolio (show, add, sell, lots, actions, list, remove, target, xray) and rebalance;
                     valuation in a base currency
                     (`value_holdings`: market quotes + `offmarket` fund NAVs and SGB prices)
    planning.rs      tax export, tax advance, portfolio benchmark (history, FX, sectors), goal sip/retire/education
    holdings.rs      watch, alert, import (Kite, INDmoney, generic CSV and `.xlsx`, tradebooks), export, wealth,
                     harvest, tax, divcal, pcorr
    imports.rs       Groww / Upstox and CAS (casparser JSON/CSV) import parsers
    sim.rs           paper-trading simulator (settle replays intraday bars)
    practice.rs      sim replay / challenge / profile / card (practice mode)
    worker.rs        daemon intraday / longterm loops
    alerting.rs      alert watch loop, notify status/test
    trade.rs         Live orders for every broker: place_live_order (validation, preview, cap, confirmation)
    broker_selftest.rs  trade selftest: read-only checks + redacted report for broker test reports
    broker_sync.rs   trade sync (trade book → lots/sales, idempotent) and trade gtt list status changes
    interfaces.rs    tui and serve (behind the `tui` / `server` cargo features)
    assistant.rs     ask and mcp (the MCP server behind the `mcp` cargo feature)
  views.rs           Data behind quote/history/markets/portfolio/watchlist/alerts as structs,
                     shared by the CLI printers, the TUI and the server; `DataSource` trait
  tui/               `stockwise tui`: app.rs (state + key handling, no I/O), ui.rs (ratatui
                     drawing), mod.rs (event loop, fetches)
  server/            `stockwise serve`: axum routes, bearer auth, Prometheus metrics; web.rs serves
                     the dashboard (web/, embedded with include_str!) and sets CSP/security headers
  daemon_status.rs   Reads the intraday daemon's daemon_state.json for /metrics
  tools/             The 35 read-only tools for AI agents, shared by `mcp` and `ask`: mod.rs (Tool
                     definitions, JSON schemas from typed Param lists, the result envelope with
                     the "not financial advice" note and size limit), args.rs (argument checks),
                     handlers.rs (each tool calls the function behind the command's --json),
                     tests.rs (also checks that the Claude Desktop manifest lists every tool)
  mcp.rs, mcp/       `stockwise mcp`: rmcp ServerHandler (tools, resources, prompts), stdio and
                     Streamable HTTP transports (`mcp` feature); mcp/tests.rs
  ask.rs, ask/       `stockwise ask`: the tool-calling loop in each provider's dialect (Ollama
                     /api/chat, OpenAI Responses, Anthropic Messages, Gemini generateContent);
                     ask/tests.rs
  store.rs           Atomic JSON persistence, data directory (STOCKWISE_HOME); `update` locks a file
                     (`<file>.lock`) around load-change-save — do network work first, then update
  config.rs          Optional config.toml: defaults for market, AI, cache, data dir, periods
  output.rs          --json / --csv rendering (Format, CsvRow, RFC 4180 quoting)
  portfolio.rs       Lots, FIFO sales, splits/dividends, XIRR cash flows, FX, named portfolios, import
                     rules (kept tradebook trades, merging, `--replace`)
  tax.rs             Capital-gains rules: holding periods, tax years, set-off, cess, sale-date rates,
                     advance tax and Sec. 234C (India/US/UK)
  tax_export.rs      ITR Schedule CG / 112A and Form 8949 schedules from realized sales, as CSV/JSON
  rebalance.rs       Target weights, drift bands and buy-only (`--inflow`) rebalancing
  xray.rs            Portfolio X-Ray: look-through overlap, asset-class, market-cap and sector split
  benchmark.rs       Daily time-weighted return vs an index, alpha/beta/tracking error, Carino attribution
  goals.rs           SIP / step-up, retirement and education math; Indian amounts (1cr, 25L, 50k)
  api.rs             Yahoo Finance client (session, quotes, charts, search, cache, retries); routes to a provider
  providers/         MarketData trait + opt-in Alpha Vantage, Massive (Polygon), Twelve Data; Yahoo fills gaps
    nse.rs, bse.rs   NSE / BSE website JSON (quotes, intraday + daily bars, search, NIFTY index members)
    session.rs       Polite exchange HTTP: one cookie session per site, ≤3 req/s with jitter, retries, refusal = stop
  i18n.rs            Typed English/Hindi message catalog, --lang / STOCKWISE_LANG / locale detection
  brokers/           Broker trait + clients: angel (SmartAPI, TOTP), zerodha, upstox, dhan, fyers
                     (experimental), secrets.rs (OS keyring / owner-only file), mock.rs (test HTTP server),
                     readonly.rs (session wrapper that refuses every order/GTT/cancel), gtt_watch.rs
                     (GTT status changes between looks), per-endpoint response shapes for selftest
  funds.rs           AMFI NAV file + api.mfapi.in history (cached), AMFI TER disclosure (cached a day),
                     returns, SIP, ETF holdings overlap
  xlsx.rs            Minimal .xlsx reader (zip via flate2 + sheet cells, tab-ordered sheets) for AMFI's TER export and broker imports
  derivatives.rs     Option chains from NSE / BSE / Yahoo, lot sizes, PCR, max pain, per-contract IV and greeks
  greeks.rs          Black-Scholes pricing, greeks, implied-volatility solver
  payoff.rs          Multi-leg option payoffs: presets, max profit/loss, breakevens, probability of profit
  commodity.rs       Gold/silver spot in ₹ from COMEX × USDINR, futures and ETF lists, SGB tranches
                     and NSE's SGB list (fixture-tested parser; `nse_sgb_list` fetches it)
  offmarket.rs       Prices for holdings Yahoo doesn't quote: `MF:` funds at AMFI's NAV, SGBs from
                     NSE's list or estimated from gold spot; used by the shared valuation
  bonds.rs           Bond math: price ↔ YTM (half-yearly, 30/360), accrued interest, duration, T-bills
  gsec.rs            CCIL tenor-wise yields, RBI benchmarks and outstanding G-sec list (HTML parsers)
  pagecache.rs       Cached fetch of public pages (CCIL, RBI, NSE SGB list) with a stale-copy fallback
  ai.rs              AI: Ollama (default) or opt-in OpenAI / Anthropic / Gemini; educational prompts
                     (`ai::prompts`, versioned cache keys), disclaimer, opt-in flag, model checks
  clock.rs           Exchange clock: IST / US Eastern / European / Sydney time, NSE, NYSE and global
                     exchange holidays and half days, lunch breaks, session phases
  daemon.rs          Worker state: positions, risk manager, daemon_state.json, shutdown, retry
                     (`daemon intraday --once` stops after one session)
  notify.rs          Notifications: Telegram, Slack, Discord, SMTP email, desktop
  technical.rs       Indicators and statistics (SMA, EMA, RSI, MACD, BB, ATR, VWAP, OBV, VaR, Sharpe, XIRR, ...)
  backtest/          Backtesting engine (see docs/backtesting.md)
    mod.rs           Daily bars from Yahoo charts
    rules.rs         TOML strategy rules: parser, validation, signals; built-ins from examples/strategies/
    indicators.rs    Whole-series indicators matching technical.rs
    costs.rs         Indian delivery/intraday and US cost models, slippage
    engine.rs        Simulator (single symbol or portfolio, fills, stops, rebalancing) and metrics
    walkforward.rs   Rolling train/test optimisation and the overfitting verdict
    plugin.rs        WASM strategy plugins: wasmi sandbox, ABI v1 (`wasm-plugins` feature)
  intraday.rs        Intraday bot (9 strategies, regime detection, Kelly sizing)
  longterm.rs        Long-term scores (6-pillar scoring, Monte Carlo, DRIP)
  simulator.rs       Paper-trading sessions and confidence rating
  practice/          Practice mode (see docs/simulator.md): scenarios/*.toml and challenges.toml
                     (embedded), scenario.rs, tape.rs (cached daily bars; reads stop at the replay
                     date), replay.rs (next-open fills with backtest costs, stops, marks),
                     challenge.rs + live.rs (rules and goals), score.rs (0–100 score, badges),
                     profile.rs (streaks, best scores), card.rs (text and SVG cards)
  insights.rs        Rule-based plain-English insights
  research.rs        One research snapshot per stock (Yahoo, NSE/XBRL filings, news) for events, insights, verdict
  events.rs          Key-events timeline: de-duplicated, categorised, with the price reaction
  verdict.rs         6-pillar score from fixed rules; pillars without data are left out, `data_coverage`
  scorecard.rs       Piotroski F-score and Altman Z (Z'') with every criterion and formula
  ipo.rs             Indian IPO board, subscription, SEBI allotment odds and 6-pillar demand score
  charts.rs          Braille line charts, option payoff chart, volume bars, gauges
  display.rs         Currency- and asset-aware formatting (₹/$/€/£/¥, FX and crypto decimals), width-aware padding
  market.rs          Market enum (in/us/crypto/fx/commodity + global exchanges), the MarketInfo table
                     (uk/de/jp/hk/sg/ca/au: suffix, currency, indices, sectors, hours, holidays, tax),
                     asset classes, symbol resolution, index/sector/coin/pair lists
  alerts.rs          Alert conditions (price, RSI, MA crosses, breakouts, day change, volume, results)
                     and their evaluation on quotes / daily bars; persisted via store.rs
  calendar.rs        Results, dividend and split dates: Yahoo calendarEvents + NSE board meetings and
                     corporate actions (one rate-limited session), day cache in calendar_cache.json
  watchlist.rs, wealth.rs   Data models persisted via store.rs

Adding a command: define it in Commands in main.rs (and in the GROUPS help table — a test enforces this), write cmd_<name> in the matching commands/*.rs file, and dispatch to it in main(). For machine-readable output, flatten TableOutput (--json/--csv) or JsonOutput (--json) into the command, build the rows once as Serialize structs, and branch on output::Format; shape tests live in commands/output_tests.rs.

Configuration

main() loads the config file before parsing arguments (config::load) and turns its market, ai and [periods] values into clap defaults, so flags and env vars still win and --help shows the effective default. Other settings are read through config::setting(env_var, ...): env var first, then the file, then the caller’s built-in default. Precedence is always flag > env var > config file > default.

Data Flow

User Input → clap CLI → commands/* → views.rs → api.rs → Yahoo Finance
              tui/, server/ ───────────↗
                                   → funds.rs → AMFI NAVAll.txt + TER disclosure, api.mfapi.in
                                   → derivatives.rs → NSE / BSE option chains (India), Yahoo (US)
                                   → gsec.rs → CCIL yields, RBI benchmarks and G-sec list (pagecache.rs)
                                   → commodity.rs ← NSE SGB list (providers/nse session)
                                            → providers/* → Alpha Vantage / Massive / Twelve Data / NSE / BSE (opt-in)
                                   → brokers/* → Angel One, Kite, Upstox, Dhan, Fyers
                                   → ai.rs → Local Ollama (or opt-in OpenAI / Anthropic / Gemini)
                                   → technical.rs (indicators)
                                   → intraday.rs / longterm.rs (bots)
                                   → charts.rs (visualization)
                                   → display.rs (formatting)
                                   → store.rs (portfolio, watchlist, alerts, history)

Caching

Hybrid cache: Redis (primary) + in-memory (fallback).

Request → Check Redis → Check Memory → Fetch Yahoo → Store Redis + Memory → Return
DataTTLWhy
Quotes30sLive prices, short freshness
Charts (1d/5d)60sIntraday data
Charts (1mo/3mo)5 minHistorical, moderate
Charts (1y+)10 minRarely changes
Search2 minStatic-ish

Redis keys use stockwise: prefix. Cache persists across CLI invocations — run stockwise deep RELIANCE, then stockwise technical RELIANCE and chart data comes from Redis.

brew services start redis       # Enable Redis caching
redis-cli keys "stockwise:*"    # See cached entries
redis-cli --scan --pattern 'stockwise:*' | xargs redis-cli del   # Clear only StockWise keys

Falls back to an in-memory cache if Redis isn’t running. Connection and response timeouts (300/500 ms) keep a missing or hung Redis from slowing commands. Point at another server with STOCKWISE_REDIS_URL (or redis_url in the config file), or set it to off.

Rate limiting: 200ms minimum between requests (5 req/sec). Retry: 3 attempts with exponential backoff; HTTP 429 honours Retry-After (capped at 10s) and never sleeps after the last attempt.

Data Storage

Location: ~/Library/Application Support/stockwise/ (macOS), ~/.local/share/stockwise/ (Linux), or %LOCALAPPDATA%\stockwise\ (Windows). Set STOCKWISE_HOME (or home in the config file) to use another directory; stockwise doctor prints the active path. Files are written atomically (temp file + rename), and broker config files are readable only by you (0600 on Unix). Broker secrets move into the OS keyring when one is available (STOCKWISE_KEYRING=off keeps them in the file).

FilePurpose
portfolio.jsonDefault portfolio: holdings with lots (qty, price, purchase date, source), realized sales, dividends. Format version 2; older files are upgraded on load and kept once as portfolio.json.bak
portfolios/NAME.jsonNamed portfolios (--portfolio NAME), same format
portfolios/NAME.wealth_history.jsonWealth history of a named portfolio
watchlist.jsonWatched symbols
alerts.jsonPrice alerts (symbol, condition, target)
wealth_history.jsonDaily value snapshots of the default portfolio
sim_history.jsonPaper trading sessions and results
sim_replay.json / sim_replay_tape.jsonThe running historical replay and its cached daily prices (removed by sim replay end)
sim_challenge.jsonA challenge running over live paper sessions
sim_profile.jsonPractice badges, streaks, best scores and recent runs
daemon_state.json / daemon_state_us.jsonThe intraday daemon’s current day (positions, risk), saved every tick
alert_watch.jsonWhich alerts alert watch already announced
angel_config.jsonAngel One API credentials (secrets in the OS keyring when available)
zerodha_config.json, upstox_config.json, dhan_config.json, fyers_config.jsonExperimental broker apps and daily sessions (secrets in the keyring when available)
cache/AMFI NAV file and per-scheme NAV history, re-downloaded after 12 hours; CCIL/RBI pages (6–24 hours) and NSE’s SGB list (5 minutes) (safe to delete)

Dependencies

CratePurpose
clapCLI argument parsing (derive macros)
clap_complete / clap_mangenShell completions and man pages generated from the CLI definition
reqwestHTTP client (Yahoo Finance, brokers, Ollama)
keyringOS keyring for broker secrets
async-traitdyn Broker with async methods
sha2 / flate2Kite/Fyers login checksums; gzipped instrument lists
rpasswordHidden prompt for pasted tokens
redisRedis caching (optional, falls back to in-memory)
tokioAsync runtime
serde / serde_jsonJSON serialization
coloredTerminal colors
chronoDate handling
dirsPlatform-specific data directories
anyhowError handling
lettreSMTP email notifications (rustls)
notify-rustDesktop notifications (optional desktop-notify feature)
ratatuiTerminal UI for tui (re-exports crossterm; tui feature)
axumHTTP server for serve (server feature)
wasmiWebAssembly interpreter for strategy plugins (optional wasm-plugins feature)
rmcpOfficial Model Context Protocol SDK for stockwise mcp, without its macros (mcp feature)

tui, server and mcp are on by default (mcp needs server); cargo build --no-default-features leaves them out (ask still works). wasm-plugins is off by default. CI-style checks should run clippy for all three builds.

Releases and packaging

Pushing a v* tag runs .github/workflows/release.yml: it builds the six release archives (binary, docs, and man/*.1 from stockwise man --dir; Linux, macOS, Windows and Android for Termux), the .deb/.rpm packages (packaging/linux/build-packages.sh, metadata in Cargo.toml) and the PyPI wheels (pyproject.toml, maturin bin), publishes the crate, renders the Homebrew, Scoop, winget and AUR manifests in packaging/ with the release’s checksums, updates the Homebrew tap and uploads to PyPI and Docker Hub when their credentials are configured, and pushes the multi-arch ghcr.io/iamsaquib8/stockwise image built from Dockerfile. flake.nix builds the same crate with Nix; packaging/nixpkgs/ and packaging/termux/ hold the nixpkgs and termux-packages recipes. .github/workflows/stats.yml archives download counts nightly (scripts/download-stats.py). See packaging/README.md.

Testing

cargo test                           # unit tests, CLI parsing tests and tests/
cargo test technical                 # only tests whose name matches
cargo test --features wasm-plugins   # also the WASM strategy plugin tests

Unit tests sit next to the code they test, and the pure engines (technical, tax, rebalance, verdict, backtest) are tested without the network. Parsers of exchange and broker pages run against fixtures in fixtures/ directories, and the HTTP clients against testutil::MockServer, so no test reaches a real service. tests/ holds the integration tests that run the built binary against a scratch STOCKWISE_HOME. Two tests read the docs: they parse every stockwise ... command written in backticks in docs/cheatsheet.md and skills/stockwise/SKILL.md, so a renamed flag breaks the build until the docs follow.

CI (.github/workflows/ci.yml) runs scripts/changelog.py check, the tests on Linux, macOS and Windows, cargo fmt --check, clippy for the default and the --no-default-features builds, a check on Rust 1.97, the wasm-plugins feature and shellcheck on install.sh.

Docs and changelog

  • docs/*.md are the documentation pages. python3 site/build.py (needs mdBook) copies them with site/index.md and site/SUMMARY.md into target/site-src, builds target/site, and writes llms.txt, llms-full.txt and a Markdown copy of every page. .github/workflows/docs.yml publishes it to GitHub Pages on every push to main.
  • changelog.d/ holds one small file per user-visible change. scripts/changelog.py checks the files and folds them into CHANGELOG.md at release time; see CONTRIBUTING.md.