Persistence Files

Runtime SQLite Records

The bot maintains all runtime state in a single SQLite database. Legacy JSON files are now only used as inputs for the migration script.

ResourceTable / FilePurpose
Unified Store arb_bot_records.sqlite3 Source of truth for all bot runtime state: open trades, metrics, go-live status, and scanner history. Managed via SQLiteStore in arb_bot/storage.py. Gitignored. Sync excludes *.sqlite3*.
Open Trades open_trades table Active positions — survives bot restarts. Holds dry-run, shadow, and live positions for all managed strategies. Replaced transactionally on every save.
Metrics metrics_days table Daily performance snapshots. Funnel counts and session stats are stored in JSON columns; executions and closed_trades are normalized into their own tables for query efficiency. Closed-trade records are deduplicated by tag - record_close ignores a tag already recorded that day, and scripts/dedupe_closed_trades.py repairs historical duplicates. Restored on restart.
Go-Live State go_live_state table Runtime paper-to-live state for all strategies. Config *_DRY_RUN flags only seed the DB on first run; thereafter, Telegram commands and the GoLiveManager own the state.
Dhan Token State runtime_state row dhan_token Latest Dhan access-token expiry, refresh source, and update time written by token_refresher.py. The raw token remains runtime state and must not be committed.
Strategy Slot State runtime_state row strategy_slots Current explicit slot occupancy, including the dc_family used/limit counts and occupying trade tags. Recomputed from persisted open_trades whenever trades are loaded or saved.
Risk Envelope State risk_envelope_state table Singleton row for daily, weekly, monthly, and lifetime P&L counters, loss-streak count, pause reason/until, and last close date. Updated after trade close and read before new-entry scanners.
AI Market Analysis ai_market_analysis table One row per AI_MARKET analysis run (Flow 1/2). OTP-confirmed /rerun_ai_market can add multiple same-day copies. Stores call time, raw response, parsed JSON, verdict, confidence, Codex token usage, error text, and downstream execution status.
AI Market Trades ai_market_trades table Mirror record for each simulated AI_MARKET option trade. Links to the analysis row and stores open tag, strike, option type, entry/exit prices, target, stop, and realised simulated P&L.
AI Shared Predictions ai_predictions table One row per market_view or breakout_risk Codex run (Flow 2 and Flow 3). Columns: date, task, payload_json (full parsed output), verdict, confidence_pct, input_tokens, output_tokens, created_at. Queried at the start of each scan cycle to apply AI hints to strategy signals. Limited to AI_PREDICT_DAILY_RUN_CAP rows per day.
AI Exit Advisories ai_exit_advisories table One row per breakout-risk exit event from the overlay (Flow 3). Columns: date, trade_tag, strategy, reason, confidence_pct, action_taken (AUTO_CLOSE or ADVISORY_ONLY), created_at. Exposed via GET /api/ai/exit-advisories and the AIPredictionsPanel dashboard component. The sentiment-risk overlay (Flow 4) reuses this table with reason="AI_SENTIMENT_RISK".
AI Market Sentiment ai_market_sentiment table One row per deterministic ~10-min sentiment run (Flow 4, SentimentService — no LLM). Columns: date, created_at, score (−100..100), label (STRONGLY_BEARISH..STRONGLY_BULLISH), strength_pct, coverage_pct, spot, prev_close, pcr, iv, components_json (per-component normalized value + weight), note. Read by the sentiment-risk exit overlay during position monitoring.
NSE Holidays nse_holidays table Cached exchange holidays used by the AI trading-day gate. Weekends are still rejected even when the holiday table is empty.
Market Events market_events table Seeded and fetched market-event risk calendar used by the option-strategy event guard, Telegram /events//why_blocked, and dashboard event APIs. Updated by make fetch-events.
Reconciliation Audit reconciliation_audit table Append-only audit rows for auto-heal actions: confirmed-flat removals, orphan adoptions, pending/confirmed quantity mismatches, and orphan alerts. The dashboard reads it through /api/reconciliation/log.
Strategy Battle Log strategy_battle_log table One row per scan cycle where scanners run. Stores per-strategy eligibility, rejection reasons, selected MDC strategy, spot, IV, realized range, and near straddle. MDC early-return reasons and IC fallback skips are recorded explicitly so an ineligible cycle explains why no new options trade was taken. Auto-pruned after 60 days.
IV Surface Snapshots iv_snapshots table One row per successful IV sample: near/far ATM IV, ATM call/put IV, skew, near/far straddles, realized range, expiries, and DTEs. Auto-pruned after 180 days; JSON payload.term_structure stores near/mid/far ATM IV and payload.smile stores bounded strike-level CE/PE IV around ATM. When Dhan omits per-leg IV, smile rows estimate CE/PE IV from option LTP using Black-Scholes inversion and mark iv_source="estimated". Snapshots also store payload.far_smile (far-expiry strikes + LTPs + IVs), which the backtest uses to reprice far-expiry legs from real recorded data instead of synthesizing them with Black-Scholes.
Trade Journal trade_journal table One row per closed trade, keyed by tag. Retains the original trade payload and captures realized P&L, exit reason, entry/exit spot and IV, skew, MFE/MAE, slippage proxies, MDC selection context, rejected strategies, the day's AI verdict, operator notes, low-cost narrative AI debrief, structured AI debrief JSON, rejected-strategy delta, AI verdict outcome, and event-risk label. Rows are written at close and can be backfilled from closed_trades, iv_snapshots, strategy_battle_log, and ai_market_analysis.
Manual Event Seed data/market_events_seed.json Operator-maintained official/seeded events such as Budget, RBI MPC, FOMC, and known CPI dates. The fetch job reloads it before source adapters.
Event Source Adapters arb_bot/event_sources/ Fetch and parse official NSE holiday, MoSPI macro, and OEA WPI source payloads into market-event rows. Parsers are tested with static payloads; runtime source failures do not abort the whole job.
Calendar Spread calendar_spread_history table Rolling z-score history (last 100 samples). Cleared on contract roll.
Security IDs futures_id_cache table Cached NIFTY near/far futures security IDs. Refreshed when near contract expires.
Runtime Config Overrides bot_settings table One row per active runtime override for a tunable Config knob. Only keys registered in arb_bot/settings/registry.py are stored here; absent row = code default. Columns: key (PK), value (raw text, coerced on read), updated_by (telegram user or "dashboard"), updated_at. The in-process cache has a 5-minute TTL and is busted instantly on write via Postgres LISTEN/NOTIFY. Edit via the dashboard /settings page or /set KEY VALUE Telegram command.
Config Change History settings_audit table Append-only log of every runtime config change. Columns: id (serial PK), key, old_value (NULL if no previous override), new_value (NULL on reset), updated_by, updated_at. Rows are never deleted — provides a full history of who changed what and when.
Logs arb_bot.log Size-capped rotating log, 50 MB per file with 7 backups. IST-aware via ISTFormatter. Telegram /logs streams only the requested tail instead of loading the whole file.

Migration from JSON

To import legacy JSON records into the SQLite database, run the importer script. It is idempotent and can be re-run safely if new files are fetched from the server.

python scripts/migrate_json_to_sqlite.py --root . --db arb_bot_records.sqlite3

Market Event Refresh

To refresh the event guard calendar from the seed file and official source adapters, run:

make fetch-events

Backtesting Records and API

The backtesting engine (arb_bot/backtest/) adds three tables to the same arb_bot_records.sqlite3 database — no new database file. They are created idempotently inside SQLiteStore._create_schema(), so reopening an existing production database migrates it automatically.

TablePurpose
bhavcopy_ohlcEnd-of-day NIFTY/BANKNIFTY option OHLC parsed from NSE UDiFF F&O common bhavcopy. Primary key (date, symbol, expiry, option_type, strike); upserts are idempotent.
backtest_runsSingle backtest runs. Stores config_snapshot, trades_json, metrics_json, and status (pending → running → complete/error).
backtest_grid_jobsGrid-search jobs. Stores the param_space and ranked results_json.

CLI

python -m arb_bot.backtest download --date 2026-06-03 --inspect-header
python -m arb_bot.backtest download --start 2026-01-01 --end today
python -m arb_bot.backtest download --status
python -m arb_bot.backtest run --strategy DC --start 2026-05-18 --end 2026-06-07 --param DC_PROFIT_TARGET_PCT=0.28
python -m arb_bot.backtest grid-search --strategy MDC --start 2026-05-18 --end 2026-06-07 --use-defaults

API + UI

The React /backtest tab drives these endpoints (all require the dashboard session cookie). Runs and grids execute asynchronously in a ProcessPoolExecutor worker so temporary Config overrides cannot leak between jobs or into the live bot.

MethodPathDescription
POST/api/backtest/runStart a single run; returns run_id.
GET/api/backtest/runsList past runs with summary metrics.
GET/api/backtest/runs/{run_id}Full trades + metrics for one run.
POST/api/backtest/grid-searchStart a grid search; returns job_id.
GET/api/backtest/grid-search/{job_id}Ranked results; UI polls until complete.