This contains all the code I have written for the signal generation and the front test where I fetch data using Dhan API
I have been running these strategies live (real broker orders) since May 2026. The day-by-day results are recorded here:
Although I own the code, the coding itself was done entirely using GPT-5.4-xhigh, GPT-5.5-xhigh, GPT-5.6 Sol xhigh and Claude Opus 4.7, Claude Opus 4.8, Claude Opus 5 on Max/Ultracode effort. GPT wrote majority of the signal generators and the data fetch files. Claude wrote the big one - the multithreaded Front Test worker. I just did the reviews and the testing. While Claude Fable 5 did one thorough audit of the whole repository
-
Data extractors which extract historical data for NIFTY/BANKNIFTY/FINNIFTY indices
-
The backtest files I used to backtest
-
The signal generators I created to generate signals
-
The main front test file which uses miltithreading to execute all strategies together
-
Live order execution to a real broker — selectable among Kotak Neo, Shoonya (Finvasia), Flattrade Pi v2, and Dhan — gated by a global kill-switch and per-strategy paper/live toggles (everything defaults to paper)
-
Live Telegram alerts: the front-test master file can post every entry/exit (option instrument, lot size, entry/exit price, and P&L) to a Telegram group/channel
-
An optional, opt-in LLM trading agent — the "SL Hunting AI Agent" — a Claude agent that trades a discretionary price-action method on NIFTY options; off by default, paper unless explicitly enabled, and fail-soft (see Recent additions)
-
An optional CPR Codex AI Agent: an independent five-minute SRSI/VWAP strategy with four frozen read-only MCP tools, deterministic host-owned execution/risk gates, safe disabled defaults, and the standard live double gate
- Crash-durable session recovery. Every entry/exit and per-strategy realized-P&L roll-up is atomically persisted during the session, while open positions are refreshed from cache every 30 seconds. A restart archives the exact prior file before writing anything, always carries same-day losses into matching workers so daily max-loss limits cannot reset, and only resumes an open position when the opt-in paper-only validation gate accepts its complete contract and risk geometry. Local shutdown completion and successful Google Sheet publication are recorded separately; see ADR-0012.
- CPR Codex AI Agent (independent, opt-in).
CPRAIWorkerfreezes session levels, momentum/VWAP, market structure, and position state once per completed five-minute bar. Codex makes a dynamic regime/setup or premise-exit judgment, while the host alone validates entry geometry, stop distance, levels, sizing, time cutoffs, lifecycle state, and execution. The worker is disabled by default and live-disabled by default; real orders require bothLIVE_TRADING_ENABLED=trueandCPR_AI_LIVE_TRADING=true, plus normal startup exposure audit/config validation. CPR, CPR Algo 3, Regime Adaptive, and CPR AI are independent strategies that may run together with independent positions and independent P&L. The approximately 27-strategy core roster can reach about 29 configured workers when both optional AI agents are enabled, while enable and virtual-trading gates keep the running roster configuration-dependent. Install the exact optional set fromrequirements-codex-ai.txt; see the focused CPR AI README for the strategy, isolation boundary, and zero-order smoke commands. - Config-drift audit —
python algo.py check-env. Settings live in three places that drift apart silently: your gitignored.env, the committedenv.exampletemplate, and the in-code default behind every_env_*call. A key present in the code and the template but missing from.envis not an error — the runner just uses the in-code default — which is what makes it easy to miss: an unseen default ends up governing a live-money run. This read-only command reports settings missing from your.env, mistyped or stale keys (a typo means the setting you intended is not being applied at all), and knobs missing from the template. It exits non-zero on findings so it can gate a pre-flight script, and prints key names only — never a value out of your.env— so its output is safe to share. CI enforces the same rule in the other direction: a new_env_*key cannot land without itsenv.exampleentry. - Per-strategy size multiplier —
<PREFIX>_SIZE_MULTIPLIER. One knob per strategy (default 1, whole numbers up to 25) that scales that strategy's entire size/risk set together: its lot count, its per-trade risk budget, its hard lot cap, and its daily max-loss kill-switch. At2a 5-lot cap becomes 10, a Rs.2,500 budget becomes Rs.5,000, a Rs.5,500 daily cap becomes Rs.11,000, and a setup that would have taken 4 lots takes 8 — so position size can grow with the account by editing one number instead of four that must be kept consistent by hand. Deliberately per-strategy only (no global switch, so one typo cannot enlarge every enabled strategy) and it applies to paper and live alike, so an enlarged size can be paper-validated first. Anything malformed (0,2.5,30,"two") falls back to 1 for paper and blocks that strategy from live trading rather than guessing a size. Leave every multiplier unset to trade exactly as before. Two consequences worth knowing: the scaled budget also loosens the "one lot exceeds the budget" skip, and because lots are floored a 2x can land slightly above a pure doubling (still strictly inside the scaled budget). For SL Hunting, note its BankNIFTY mirror already roughly doubles basket risk, so a multiplier of M leaves the basket near 2xM times the single-leg budget. - Optional websocket market data producer —
MARKET_DATA_SOURCE=WEBSOCKET. The runner can now source its market data from Dhan's marketfeed websocket instead of REST polling (requires Dhan's paid Data API subscription; any other value of the flag fails closed to the default REST poller). Ticks build the 1-minute candles live — the forming minute updates in real time — and once per minute the completed candles are trued-up against Dhan's official REST candles (official wins; divergence is logged), so strategy bars converge to exactly what the backtests used. All LTPs (NIFTY spot plus every subscribed option leg, including multi-leg baskets: hedged pairs, Delta-0.2's four legs, strangle legs, the SL Hunting BankNIFTY mirror) stream from ticks in real time, with legs subscribed/unsubscribed dynamically as workers enter and exit. REST stays for warmup history and reconnect gap-backfill; API load drops from one full-window pull every 2-5s to ~1/minute. The market-data health gates (10s LTP / 150s bar / 30s liquidation) behave identically, with one tick-feed-aware twist: quiet-but-subscribed legs stay fresh only while the socket is demonstrably alive. Rollback isMARKET_DATA_SOURCE=REST+ restart; the tick logic lives inDependencies/tick_bar_builder.py. - Per-strategy "off" switch —
<PREFIX>_VIRTUAL_TRADING. Every strategy now has a virtual (paper) toggle that defaults to true. Set it false to stop that strategy's worker thread from starting at all — so it does no paper trading (and, since the thread never runs, no live trading either). Unlike live trading there is no global master switch: the default is that everything runs, and you silence individual strategies. Lets you run just the strategies you want on a given day instead of the whole roster. - Quality gates & CI. A GitHub Actions workflow (
.github/workflows/quality-and-security.yml) runs the full gate on every push/PR across Python 3.12 + 3.13: all repository suites, branch-coverage budgets,pip-audit,compileall, Ruff, mypy (scoped inpyproject.toml), Bandit, and pre-commit validation. Exact tooling lives inrequirements-dev.txt. - SL Hunting AI Agent — BankNIFTY mirror basket + newer knowledge (v3c–v3e). The agent now trades Intraday Hunter's multi-index style: every NIFTY entry is mirrored with an equal-lot BankNIFTY ATM leg (
SL_HUNTING_BNF_MIRROR, default true). The two legs are tied for hard risk (stop/target, max-loss, 15:15 square-off close both) but the agent evaluates each leg's premise independently and can cut one alone via the EXITexit_legselector (NIFTY|BNF|BOTH). Entry stays NIFTY-only (the mirror copies it). Its knowledge also grew several distilled-from-video layers — a scoped gap-up opening-drive, a 2-week verbatim transcript sweep, and a live-day match against the agent's own journal (details inSignal Generators/SL Hunting AI Agent/README.md). - Optional LLM trading agent — the "SL Hunting AI Agent" (opt-in worker). A Claude agent (via the
claude-agent-sdkon your Claude subscription — no API key) trades the discretionary SL Hunting price-action method on NIFTY ATM options. Once per completed 1-min bar (the method's native timeframe) it reads the NIFTY chart (with BankNIFTY cross-confirmation) and — only on a confirmed setup at a real level — acts through the SAME testedenter_position/exit_positionpath as every other worker. Position sizing floors affordable whole lots, never exceedsSL_HUNTING_RISK_BUDGET, skips one-lot-over-budget setups, and caps atSL_HUNTING_MAX_LOTS(default 5); the equal-lot BankNIFTY mirror can roughly double basket risk. It stops opening new positions after 10:30 (SL_HUNTING_NO_NEW_ENTRY_HOUR/_MINUTE, default 10:30) — not a square-off: open positions, their stops/targets, and the 15:15 square-off are unaffected. Its post-exit cooldown starts only when the whole NIFTY/BankNIFTY basket is confirmed flat, so an independently surviving or partly closed leg cannot run the timer down; exits never consult this guard, while unreadable guard state rejects new live entries. It is off by default (SL_HUNTING_ENABLED), trades paper unless bothLIVE_TRADING_ENABLEDandSL_HUNTING_LIVE_TRADINGare set, and is fail-soft — any agent/SDK error becomes a safe HOLD while its separate mechanical risk loop keeps checking stop, target, max-loss, stale data, and square-off. It can also learn from its own trades through a tool-free, schema-validated reflection coach with digest-bound human approval (paper-first, off by default). Install the exact optional stack withpip install -r requirements-ai.txtand run one-timeclaude setup-token(keepANTHROPIC_API_KEYUNSET so it bills your Claude plan, not per-token API). Full details — knowledge, tools, safety model, the learning loop — are inSignal Generators/SL Hunting AI Agent/README.md. It joins the configuration-dependent worker roster only when enabled. - CPR Algo 3 (multi-instrument) is now wired into the front test. A new
CPRAlgo3StrategyWorkerruns the "CPR basic setup" strategy, which watches THREE charts at once — the NIFTY spot plus a ~ITM CE and a ~ITM PE of the current-week expiry — and only fires when VWAP and the CPR band align across all three (RSI/ARSI on spot). The two ITM options are observation only: a signal still BUYS the ATM CE/PE of the next-next expiry through the same tested path as the other directional workers, so it shares CPR's risk knobs (tunable viaCPR_ALGO3_*in.env, includingCPR_ALGO3_ITM_OFFSET). It fetches the two option 1-min OHLC feeds on demand and drives its own spot target/stop exit. It belongs to the core roster, while the enabled total remains configuration-dependent. (The standalone Algo 3 signal generator + its unit tests live underSignal Generators/CPR Strategy/.) - Code-quality pass. Added a
requirements.txt; gave every Shoonya broker HTTP call a timeout (a hung call could otherwise stall a worker thread and the shared broker lock); removed hardcoded credentials from the vendored Shoonya client; routed the execution layer's status/errors throughlogginginstead ofprint(); and ported the master test suite into the repo (Tests/test_nifty_multi_strategy_master.py— see Tests below). - Live broker execution is broker-selectable (Kotak Neo, Shoonya, or Flattrade).
LIVE_BROKERpicksKOTAK,SHOONYA, orFLATTRADE, and every real order goes through one genericexecution_client. The globalLIVE_TRADING_ENABLEDkill-switch and each strategy's<PREFIX>_LIVE_TRADINGflag must both be true; unknown broker names fail closed to paper. Each broker folder contains an execution client and a read-only diagnostic with an optional, typed-YES, round-trip test order. Flattrade uses its official Pi v2 browser-token flow, exact NFO index scrip master, documented request limits, market-order protection, andSingleOrdHistfill confirmation. Everything still defaults to paper. (Shoonya's legacy QuickAuth endpoint is being decommissioned by Finvasia.) - End-of-day P&L is now written to a Google Sheet. When all workers exit on a clean end of day, the master parses the run's log for each strategy's realised P&L and writes it into a tracker sheet — one row per strategy, one column per calendar day — overwriting today's cell and backfilling any blank earlier-this-month cells from the (append-mode) log. Auth is OAuth user-token via
gspread; configureGSHEET_ID+ an OAuth client in.env(see Setup). It's a safe no-op when unconfigured, so it never disturbs shutdown. - 13 TradingBot signal-generator ports. Thirteen ATM single-leg strategies were ported into
Signal Generators/(SMA Crossover, Bollinger Bands, Keltner Squeeze, Mean Reversion Z-Score, ML Ensemble, Multi-Timeframe, Opening Range Breakout, Parabolic SAR, RSI Divergence, RSI Reversal, Stochastic, Supertrend, Volatility Breakout), all sharingmisc_strategy_common.pyand the mandatory TA-Lib 0.6.8 indicator backend. They're wired through the sharedAtmSingleLegStrategyWorkerfactory and each is tunable from.envby its own prefix. ML Ensemble needsscikit-learn. - Regime Adaptive — one router, two rules. A fourteenth port through the same factory, but from a different project (
workratananmol-hub/nifty-options-paper-trading-bot, MIT). Instead of one rule it reads ADX each bar and switches: an opening-range breakout confirmed by VWAP when the market trends, a fade back to VWAP when it ranges, and no trade at all when ADX is missing — it never guesses the regime. The two candidate rules live inRegime Adaptive Strategy/regime_candidates.pyas library code with no worker of their own, so the router can never double up on a candidate's signal. Tunable byREGIME_ADAPTIVE_*. ReadSignal Generators/Regime Adaptive Strategy/REGIME_PORTING_NOTES.mdbefore enabling it live: this runner receives no volume, so its VWAP is an equal-weight proxy. The source's India VIX and breadth vetoes are not implemented — absent by choice rather than for want of data (the source project runs on Dhan too). - Bid/ask spread gate —
<PREFIX>_MAX_SPREAD_PCT. Every strategy here BUYS options, so a 2%-of-mid spread is a 2% loss booked at the moment of entry, before the idea has done anything. The runner now readstop_bid_price/top_ask_priceoff the/optionchainresponse for the exact strike and expiry being bought and refuses an entry quoted wider than the cap. A too-wide spread is refused in paper and live alike (it's a market fact, so paper rows stay predictive); an unreadable quote refuses live only and lets paper through with a warning (an API failure shouldn't cost you a paper data point, but it also shouldn't spend real money on a check that didn't run). Workers share one 3-second cache because Dhan allows a single option-chain request per 3s per underlying/expiry. Default0— off — for every strategy except Regime Adaptive (2.0), so no existing strategy's behaviour changed. - CPR (Central Pivot Range) strategy is now live in the front test. It runs as an ATM single-leg worker (
CPRStrategyWorker) alongside the other strategies: the master file feeds it 1-min OHLC, the CPR logic resamples to complete 5-min candles internally, and a LONG/SHORT signal buys the ATM CE/PE of the next-next expiry. Tunable viaCPR_*knobs in the.env(lots, max-loss, poll, 09:25-15:15 window). (This brought the master file to nine workers at the time; the running roster is now configuration-dependent.) - Telegram trade notifications. A queue-based
TelegramMessageWorkerposts a message to a Telegram group/channel on every entry and exit from any worker. Each alert shows the strategy, the exact option instrument(s), lot size, entry and exit price, and P&L (hedged spreads show both legs). It runs on its own thread so Telegram latency or downtime never blocks the trading loop, and it's a cheap no-op when disabled. See Setup below to switch it on.
You might have to adjust the import addresses from which the files are to be imported because the files are in different directories in my local machine(fixed in the latest Claude commit)
.
├── Nifty Multi Strategy Front Test - Master File.py # ~27 core strategies + independently opt-in agents
├── Data Extractors/ # 1m OHLC downloaders + shared helper
├── My Backtest Files (For Reference)/ # backtesting.py-based backtests
├── Signal Generators/ # strategy / signal logic modules
├── Tests/ # EVERY test, mirroring the tree above
├── docs/ # architecture docs: hld/, lld/, adr/
└── Dependencies/ # shared config + live-execution layer
├── env.example # copy to Dependencies/.env and fill in
├── dhan_token_setup.py # one-time DhanHQ OAuth token setup
├── Kotak API/ # kotak_execution.py + diagnose_kotak_symbol.py
├── Shoonya API/ # NorenApi.py + shoonya_execution.py + diagnose_shoonya_symbol.py
├── Flattrade API/ # flattrade_execution.py + diagnose_flattrade_symbol.py
└── Dhan API/ # dhan_execution.py + diagnose_dhan_symbol.py
Each subfolder has its own Readme.md with the details.
-
Python 3.10+ (I'm running 3.13).
-
Install dependencies:
pip install -r requirements.txtThat covers the core (data fetch, backtests, runner). Install exact optional sets only when needed:
pip install -r requirements-ai.txt # SL Hunting Claude SDK stack pip install -r requirements-codex-ai.txt # CPR Codex SDK + local MCP stack pip install -r requirements-dev.txt # local quality/security gates pip install pyotp==2.9.0 websocket-client==1.8.0 # Shoonya runtime pip install --no-deps "git+https://github.com/Kotak-Neo/Kotak-neo-api-v2.git@v2.0.1#egg=neo_api_client"Flattrade uses the core
requestsandpandasdependencies. Shoonya's NorenApi client is vendored. Kotak's official tag declares older exact pandas/requests versions, so--no-depsprevents it from silently downgrading the audited core runtime.requirements-brokers.txtrecords and tests the upstream broker dependency environment separately in CI; do not combine it withrequirements.txt. -
Configure credentials. Copy
Dependencies/env.exampletoDependencies/.envand fill it in (.envis git-ignored). Set your Dhan credentials there, then run the one-time token setup:python "Dependencies/dhan_token_setup.py"It walks you through the DhanHQ OAuth login and writes a fresh
DHAN_ACCESS_TOKENback into.env. All tunable strategy parameters live in this same.env. -
(Optional) Turn on Telegram trade alerts by adding these to the master file's
.env:TELEGRAM_ENABLED=true TELEGRAM_BOT_TOKEN=your_botfather_token TELEGRAM_CHAT_ID=@your_channel_or_-100xxxxxxxxxxCreate the bot via @BotFather and add it to your group/channel as an admin. Leave
TELEGRAM_ENABLED=false(the default) to run without alerts. The token stays in.env, which is git-ignored. -
(Optional) End-of-day P&L to Google Sheets. After all workers exit, the master writes each strategy's day-end P&L into a tracker sheet (one row per strategy, one column per day, with month backfill). Enable it by adding to the master's
.env:GSHEET_ID=your_spreadsheet_id GSHEET_OAUTH_CLIENT_FILE=Dependencies/gsheet_oauth_client.json GSHEET_OAUTH_TOKEN_FILE=Dependencies/gsheet_oauth_token.jsonAuth is OAuth user-token via
gspread: in Google Cloud enable the Sheets API, create an OAuth client of type Desktop app, download its JSON toGSHEET_OAUTH_CLIENT_FILE, and share the sheet with your Google account. The first run opens a browser once for consent and caches a token atGSHEET_OAUTH_TOKEN_FILE. PAPER results use the existing row labels in column A (e.g.Renko Strategy); LIVE and MIXED results use separateRenko Strategy [LIVE]andRenko Strategy [MIXED]rows so real-money outcomes cannot contaminate paper history. Unmatched strategies are skipped with a warning. LeaveGSHEET_IDblank to disable (safe no-op). -
(Optional) Live broker execution. Everything is paper by default. To place REAL orders, set in
Dependencies/.env:LIVE_TRADING_ENABLED=true # global kill-switch (default false) LIVE_BROKER=KOTAK # KOTAK, SHOONYA, FLATTRADE, or DHAN RENKO_LIVE_TRADING=true # flip the specific strategies you want liveThen fill the selected broker's credential block. Flattrade needs
FLATTRADE_CLIENT_ID,FLATTRADE_API_KEY, andFLATTRADE_API_SECRET; its optionalFLATTRADE_ACCESS_TOKENis validated when supplied, otherwise startup opens browser authorization and asks for the returnedrequest_code. A strategy trades live only whenLIVE_TRADING_ENABLEDand its own<PREFIX>_LIVE_TRADINGare both true. An entry falls back to paper only after a typed zero-fillREJECTED;PARTIALorUNKNOWNmeans exposure may exist, freezes new live entries, and starts reconciliation. Check connectivity first with the read-only diagnostics — they can place a confirmation-gated round-trip (buy + auto square-off) test order via--place-order:python "Dependencies/Kotak API/diagnose_kotak_symbol.py" CE 23950 --place-order python "Dependencies/Shoonya API/diagnose_shoonya_symbol.py" CE 23950 26JUN25 --place-order python "Dependencies/Flattrade API/diagnose_flattrade_symbol.py" CE 24150 14JUL26 --place-order python "Dependencies/Dhan API/diagnose_dhan_symbol.py" CE 24150 14JUL26 --place-order
algo.py is a single entry point for every script in this repo via short commands. It just launches the underlying scripts (so each one still works on its own), and any flag beyond the selector passes straight through. From the repo root:
| Command | What it does | Example |
|---|---|---|
fetch-data --index {nifty,banknifty,finnifty} |
Download 1-min OHLC for an index | python algo.py fetch-data --index nifty --interval 5 --lookback 5y |
backtest --strategy {renko,ema,heikin,cpr,profit-shooter,goldmine,money-machine} |
Backtest one strategy against a CSV | python algo.py backtest --strategy renko --data "Backtest Outputs/nifty_renko_futures_5y_1min_data.csv" |
run |
Start the front-test master (paper by default; live per .env) |
python algo.py run |
setup-token |
One-time DhanHQ token setup (writes .env) |
python algo.py setup-token |
diagnose --broker {kotak,shoonya,flattrade,dhan} |
Read-only broker/symbol check (add --place-order for a test order) |
python algo.py diagnose --broker flattrade CE 24150 14JUL26 |
check-env |
Read-only audit of .env vs env.example vs the settings the code reads |
python algo.py check-env |
Run python algo.py --help, or python algo.py <command> --help, for the details.
- Pull historical data — e.g.
python "Data Extractors/Nifty 1m 5Y Data Fetch Dhan.py". The CSV lands inBacktest Outputs/. - Run a backtest against that CSV — e.g.
python "My Backtest Files (For Reference)/Nifty Renko Strategy Backtest.py". - Once a strategy looks good, run
Nifty Multi Strategy Front Test - Master File.pyfor multi-strategy execution — paper by default, or live once you've configured a broker (Setup step 6).
(Or do all three with the unified CLI above: python algo.py fetch-data --index nifty → python algo.py backtest --strategy renko --data ... → python algo.py run.)
The Backtest Outputs/ folder is .gitignore-d, so generated CSVs/logs stay local.
Every test in this repository lives under Tests/, mirroring the source tree — the tests for Signal Generators/SL Hunting AI Agent/ are at Tests/Signal Generators/SL Hunting AI Agent/, and so on. Runtime folders contain only runtime code.
The front-test master has a unittest suite — env toggles, broker paper/live routing and the fail-closed LIVE_BROKER switch, order fill-confirmation, and symbol resolution. Run it from the repo root:
python -m unittest Tests.test_nifty_multi_strategy_master
Broker/SDK-specific cases skip automatically when optional dependencies are absent, and all broker HTTP/browser/order behaviour is mocked. Signal generators, execution/reconciliation primitives, data extractors, and repository-policy checks have focused suites at their mirrored paths. CI runs the whole quality gate on every push/PR — see "Quality gates & CI" below.
Adding a test? Put it at the mirrored path, and give it a filename that is unique across the repository — pytest keys modules by basename (there are no __init__.py files). Where a Tests/ folder mirrors a source folder whose name contains spaces, it carries a conftest.py that puts the source folder on sys.path, so tests resolve imports exactly the way the runner does. The reasoning is in docs/adr/0010-tests-in-a-mirrored-tests-tree.md.
A GitHub Actions workflow (.github/workflows/quality-and-security.yml) runs on every push and pull request across Python 3.12 and 3.13. Locally, the same gate is:
pip install -r requirements-dev.txt
pip install -r requirements-ai.txt
pip install -r requirements-codex-ai.txt
python -m unittest Tests.test_nifty_multi_strategy_master
python -m unittest Tests.test_market_data_health
python -m pytest "Tests/Signal Generators" "Tests/Dependencies" "Tests/Data Extractors" -q
python -m coverage erase
python -m coverage run -m unittest Tests.test_nifty_multi_strategy_master
python -m coverage run --append -m unittest Tests.test_market_data_health
python -m coverage run --append -m pytest "Tests/Signal Generators" "Tests/Dependencies" "Tests/Data Extractors" -q
python -m coverage json -o coverage.json
python scripts/check_coverage_thresholds.py coverage.json
python -m pip_audit -r requirements.txt --no-deps --progress-spinner off
python -m pip_audit -r requirements-ai.txt --no-deps --progress-spinner off
python -m pip_audit -r requirements-codex-ai.txt --no-deps --progress-spinner off
python -m pip_audit -r requirements-dev.txt --no-deps --progress-spinner off
python -m compileall -q .
python -m ruff check .
python -m mypy
Coverage is branch-enabled: overall runtime coverage may not fall below 68% (CI measures 69.1%; a local run with the optional broker SDKs installed reads ~2 points higher because 7 SDK-gated tests skip in CI — trust the CI number), new execution/reconciliation/data-safety modules require 90%, and every broker adapter requires 80%. The four local audit commands check committed direct pins; CI additionally audits the complete resolved dependency tree in a clean hosted environment. pyproject.toml holds the coverage, Ruff, and mypy config (mypy is scoped to the identifier-named modules — the spaced-name master file is covered by compileall + the unittest suite instead). .pre-commit-config.yaml wires the check-only hooks; install them once with pre-commit install.
Released under the MIT License — see LICENSE.