A junior quant risk analyst, automated — across both the markets desk and the accounting desk.
Showcase site → · Live dashboard →
Sentinel is an open-source agentic financial risk engine that unites two analyst disciplines in one system: a market-risk lens (CFA-style) and a forensic-accounting lens (CA-style). It ingests market prices, macro factors and SEC filings; computes the full risk battery (volatility, Value-at-Risk, Expected Shortfall, CAPM and Fama-French factor exposures, Markowitz portfolio optimization); reads 10-K financial statements to run DuPont, Altman Z-score, Piotroski F-score, Beneish M-score and Benford's Law screens; detects anomalous market days with machine learning (a PyTorch autoencoder + IsolationForest); maps systemic risk as a correlation network; runs macro stress tests; and uses an LLM agent with tool access to the whole engine to write the analyst risk memo — served via a FastAPI REST API, a Docker container, and a Streamlit dashboard.
It goes beyond measurement into decisions: a supervised stress-day classifier (logistic regression + random forest) predicts drawdowns and, in a fully walk-forward backtest, gates the portfolio's allocation; semi-supervised label propagation surfaces the anomaly near-misses two detectors disagreed on; KNN analog days retrieve what historically followed markets like today; and PCA / KMeans plus Marchenko-Pastur covariance denoising clean the optimizer's inputs. Every technique is tied to a real, verified result rather than shown for its own sake.
| What it is | End-to-end agentic quant risk + forensic-accounting engine |
| Two lenses | Market risk (CFA) · Fundamental & forensic accounting (CA) |
| Data (all free, no paid keys) | yfinance prices · SEC EDGAR 10-K XBRL · Ken French factor library |
| Risk models | Historical + Cornish-Fisher VaR, Expected Shortfall, Sharpe/Sortino/Calmar, CAPM, Fama-French 5+momentum, Euler risk decomposition, Kupiec backtest, Markowitz efficient frontier |
| Accounting models | Liquidity/solvency/profitability ratios, DuPont ROE, Altman Z, Piotroski F, Beneish M, accruals, Benford's Law |
| ML | IsolationForest + PyTorch autoencoder anomaly detection · supervised stress-day classifier (logistic + random forest) · semi-supervised label propagation · PCA + KMeans + Marchenko-Pastur denoising · KNN analog days |
| Decision layer | Walk-forward tactical backtest — the classifier gates the allocation (max-Sharpe book: max drawdown -42% → -28%); denoised covariance lowers realized out-of-sample vol |
| Agent | Claude (claude-opus-4-8) with 12 tools over the engine; deterministic template fallback with no API key |
| Surfaces | 16 REST endpoints · 12-tab Streamlit terminal · Next.js showcase site |
| Tested | 120 pytest cases, known-input & closed-form oracles, no network needed |
| Stack | Python · pandas · NumPy · SciPy · scikit-learn · PyTorch · NetworkX · DuckDB · FastAPI · Docker · Streamlit · Plotly · Next.js |
Sentinel doubles as the applied capstone for the IITG.ai
"ML.AI" summer course on Data Science & Machine Learning.
docs/COURSE_MAPPING.md maps every week — supervised
regression & classification, PCA, clustering, ensembles, semi-supervised
learning, neural networks — to the Sentinel module that puts it to work, then
closes the loop in a decision layer: the stress classifier gates a
walk-forward allocation (cutting the max-Sharpe book's worst drawdown from
-42% to -28%), label propagation surfaces the anomaly near-misses the two
detectors disagreed on, KNN retrieves what followed the days most similar to
today, and random-matrix denoising hands the optimizer a cleaner covariance
that realizes lower out-of-sample volatility.
Every risk desk runs the same daily loop: pull prices, recompute metrics, eyeball charts for anything weird, stress the book, and write a memo about it — hours of skilled-analyst time producing a report about yesterday. Meanwhile a second discipline entirely — the accountant's loop of reading filings for distress and earnings manipulation — usually lives in a different team and a different spreadsheet. The interesting question isn't whether each step can be automated (it can); it's whether the whole loop across both disciplines can run end-to-end without a human in the middle.
Sentinel is that loop as software, in two lenses.
- The full risk battery — annualized volatility, historical & Cornish-Fisher VaR, Expected Shortfall (the coherent tail measure Basel FRTB standardized on), Sharpe/Sortino/Calmar, CAPM vs SPY, and a rolling out-of-sample Kupiec VaR backtest.
- Factor attribution — a Fama-French 5-factor
- momentum regression that separates style exposure from genuine skill, reporting factor-adjusted alpha with t-stats.
- Allocation — Markowitz mean-variance optimization: the efficient frontier plus min-variance, max-Sharpe (tangency) and risk-parity portfolios versus the equal-weight book.
- Anomaly detection with two independent ML models — an IsolationForest baseline and a PyTorch autoencoder that learns to reconstruct "normal" market days. Neither is told anything about events; their agreement is the signal.
- Structure, not just numbers — a correlation network (NetworkX) that ranks systemic importance by eigenvector centrality and flags correlation drift.
- Financial-statement analysis straight from SEC EDGAR XBRL: liquidity, solvency, profitability and efficiency ratios plus a 3-step DuPont decomposition of return on equity.
- Forensic screens — Altman Z-score (bankruptcy risk), Piotroski F-score (fundamental quality), Beneish M-score (earnings-manipulation detection — the model that flagged Enron), an accruals ratio, and Benford's Law digit analysis across every reported figure. This is anomaly detection applied to the financial statements instead of the price.
- A GenAI agent with tool access to the entire engine (not a prompt full of pasted numbers) answers free-text questions and writes the structured, two-lens risk memo, ending in a recommendation.
Every non-obvious modeling choice is documented in the code with a short "why" comment; every layer has tests with known-input and closed-form sanity checks; and the factor and optimization math was independently cross-verified.
yfinance ─┐ ┌─ MARKET RISK (CFA) ───────────────────────────┐
(prices) ├─▶ DuckDB warehouse ─▶ │ risk battery · Fama-French factors · Markowitz │
Ken French┘ (returns in SQL) │ anomaly (IF+AE) · corr network · stress engine │
(FF5+mom) └────────────────────────────────────────────────┘
┌─ ACCOUNTING RISK (CA) ─────────────────────────┐
SEC EDGAR ─────────────────────▶ │ ratios · DuPont · Altman/Piotroski/Beneish │
(10-K XBRL companyfacts) │ accruals · Benford's Law │
└───────────────────────┬────────────────────────┘
▼
Claude agent (9 tools) ─▶ risk memo (MD/PDF)
│
▼
FastAPI (10 endpoints · Docker) · Streamlit (10 tabs) · Next.js site
1. Both anomaly models independently rediscovered the two real stress events from raw returns alone. 43 flags each (calibrated to a 2% base rate), 14 days of agreement: the March–April 2020 COVID crash cluster and April 9, 2025 (the tariff-pause day). No event data, no labels, no news feed.
2. The correlation network recovers the economy's sector structure with zero labels — greedy-modularity communities on daily-return correlations split the book cleanly into tech, cyclicals, and defensives, with systemic risk concentrating in the tech/cyclical core.
3. Diversification works — until it doesn't. The equal-weight portfolio's volatility (18.7% ann.) is below every single constituent, but the 2008-style stress scenario produces a −97% drawdown: when correlations go to one, sector diversification is no defense.
| scenario | ann. vol | VaR 95 | max drawdown |
|---|---|---|---|
| baseline | 18.7% | 1.69% | −30.0% |
| rate_shock | 24.3% | 2.26% | −38.8% |
| sector_shock_tech | 26.2% | 2.47% | −49.2% |
| market_crash_2008_style | 46.7% | 4.56% | −97.2% |
4. The factor model finds real alpha; the forensic screens find real signal. A Fama-French 5+momentum regression explains R² = 0.90 of the portfolio's variance (market β 0.94, large-cap and quality tilts) and leaves a factor-adjusted alpha of +7.5% (t = 3.73) — skill that survives stripping all six style factors. On the accounting side, DuPont cleanly separates Apple's ~152% ROE (margin × leverage) from Walmart's ~21% (asset turnover), while the Beneish M-score flags NVIDIA — the textbook hyper-growth false positive the memo calls out rather than treating as a verdict.
| Component | Role |
|---|---|
src/ingest/market.py |
Daily OHLCV via yfinance; parquet cache; gap handling that bridges halts but never invents pre-listing history |
src/ingest/edgar.py |
SEC EDGAR XBRL companyfacts loader; resilient concept-picker across evolving us-gaap tags; annual 10-K figures |
src/ingest/factors.py |
Fama-French 5 + momentum daily factors from the Ken French Data Library |
src/warehouse/duck.py |
DuckDB warehouse; returns derived in SQL so every consumer shares one source of truth |
src/models/risk.py |
Vol, historical + Cornish-Fisher VaR, Expected Shortfall, Sharpe/Sortino/Calmar, CAPM vs SPY, Euler risk-contribution decomposition, rolling Kupiec VaR backtest |
src/models/factors.py |
Hand-rolled OLS factor regression; factor loadings, t-stats, R², factor-adjusted alpha |
src/models/optimize.py |
Markowitz efficient frontier; min-variance, max-Sharpe, risk-parity portfolios (SciPy SLSQP, long-only) |
src/models/fundamentals.py |
Financial-statement ratios + 3-step DuPont ROE decomposition |
src/models/forensic.py |
Altman Z, Piotroski F, Beneish M, accruals, Benford's Law forensic screens |
src/models/anomaly.py |
IsolationForest + autoencoder (20→8→3→8→20) over per-name returns and rolling vol; agreement flag |
src/models/classify.py |
Supervised stress-day classifier: L2-logistic + random forest on forward-drawdown labels; chronological split, time-series CV, ROC-AUC / precision / recall |
src/models/unsupervised.py |
PCA statistical factors (PC1 ≈ the market) + KMeans peer clustering on correlation profiles; Marchenko-Pastur covariance denoising with an out-of-sample check |
src/models/tactical.py |
Walk-forward tactical backtest: the stress classifier gates the book between min-variance and the aggressive portfolio; costs, regime log, honest two-sided result |
src/models/semisup.py |
Semi-supervised anomaly hunt: label propagation from confirmed events surfaces the near-miss days the detectors disagreed on |
src/models/analogs.py |
KNN analog days: the k most similar historical days to today + the forward month that followed each |
src/models/graph.py |
Correlation network, eigenvector centrality, communities, 63-day correlation-shift detector |
src/models/stress.py |
Parameterized scenario engine (vol multiplier + drift shocks) replayed over history |
src/agent/memo.py |
Claude agent with 9 tools over the engine; writes the two-lens memo, answers questions; deterministic fallback without a key |
src/api/main.py |
FastAPI: /metrics, /stress, /anomalies, /fundamentals, /forensic, /factors, /allocation, /credit, /classify, /clusters, /tactical, /analogs, /candidates, /ask, /memo, /health |
dashboard/ |
Streamlit risk terminal — dark, mint-accent, twelve tabs including Forensic, Factors, Allocation, ML Models, Tactical and "Ask the Agent" |
site/ |
Next.js + Tailwind + framer-motion showcase page (Vercel) |
# 1. Environment
python -m venv .venv && .venv\Scripts\activate # Windows (source .venv/bin/activate on unix)
pip install -r requirements.txt
copy .env.example .env # optional: add ANTHROPIC_API_KEY for the AI memo
# 2. Pick your surface
pytest # 80 tests, no network needed
uvicorn src.api.main:app --port 8000 # API -> http://localhost:8000/docs
streamlit run dashboard/app.py # dashboard -> http://localhost:8501
docker compose up --build # containerized API
# 3. Showcase site
cd site && npm install && npm run dev # -> http://localhost:3000Everything bootstraps its own data on first run (yfinance → DuckDB, EDGAR and
Ken French cached to parquet with committed fallback snapshots). Without an
ANTHROPIC_API_KEY the agent degrades gracefully to a templated memo filled with
the real computed numbers.
- Batch, not streaming. Data refreshes on demand. The natural next step is a Kafka ingestion topic with Spark/Flink computing rolling metrics continuously, DuckDB swapped for a real warehouse, and anomaly scoring served online.
- Single asset class, daily bars. The metric layer is shape-agnostic, so rates/FX/crypto and intraday bars are config away — the interesting work is recalibrating the anomaly base rate.
- Forensic models are calibrated for operating companies. Altman and Beneish don't apply cleanly to banks and regulated utilities; Sentinel excludes them explicitly rather than reporting a misleading number.
- Stress scenarios are stylized. Vol-multiplier + drift shocks are transparent and committee-explainable; historical bootstrapping or factor-model shocks would be the production upgrade.
What is Sentinel? An agentic quantitative risk and forensic-accounting engine — a Python system that automates two analyst workflows in one: the market-risk desk (risk metrics, factor models, portfolio optimization, ML anomaly detection, stress testing) and the forensic-accounting desk (financial-statement analysis and earnings-manipulation screens), capped by an LLM agent that writes a decision-oriented risk memo.
What financial risk and accounting models does it implement? Market: volatility, historical & Cornish-Fisher Value-at-Risk, Expected Shortfall, Sharpe/Sortino/Calmar ratios, CAPM, Fama-French 5-factor + momentum regression, Euler (component) risk decomposition, Kupiec VaR backtest, and Markowitz mean-variance optimization. Accounting: liquidity/solvency/profitability/ efficiency ratios, DuPont ROE decomposition, Altman Z-score, Piotroski F-score, Beneish M-score, accruals ratio, and Benford's Law.
How does the AI agent work? Genuine tool use, not pasted numbers: a Claude model is given twelve callable tools over the engine (risk summary, anomalies, network, stress, fundamentals, forensic scores, factor model, portfolio optimization, distance-to-default, analog days, tactical backtest) and decides which to call. Without an API key it degrades to a deterministic template memo, so the whole system runs offline.
What is the Altman Z-score, and how does Sentinel use it? The Altman Z-score is a bankruptcy-risk model combining five financial ratios; above ~2.99 is the "safe" zone, below ~1.81 is distress. Sentinel computes it per company from SEC filings, using the market value of equity, and plots each name against the distress zones.
What is the Beneish M-score? An eight-variable model that estimates the probability a company is manipulating its earnings; a score above −1.78 flags a likely manipulator. It famously scored Enron as a manipulator before its collapse. Sentinel computes it from year-over-year changes in the financial statements and captions the well-known caveat that fast-growing companies can trip a false positive.
What is the Piotroski F-score? A nine-point checklist of fundamental health (profitability, leverage/liquidity, operating efficiency); 8–9 is strong, 0–2 is weak. Sentinel scores every holding.
What is Benford's Law used for here? Benford's Law predicts the frequency of leading digits in naturally occurring numbers. Auditors use deviations from it to flag manipulated figures; Sentinel runs a first-digit conformity test (with Nigrini's mean-absolute-deviation thresholds) across every reported financial figure.
What is DuPont analysis? A decomposition of return on equity into net margin × asset turnover × equity multiplier — showing why a firm earns its return. Sentinel uses it to contrast, e.g., a high-margin/leverage name like Apple against a high-turnover retailer.
What is a Fama-French factor model and "factor-adjusted alpha"? A regression of portfolio returns on academic style factors (market, size, value, profitability, investment, momentum). The intercept — factor-adjusted alpha — is the return that survives after accounting for those known style premia, a far higher bar than raw or CAPM alpha.
What is the efficient frontier / Markowitz optimization here? Sentinel computes the set of portfolios with the best return for each level of risk (the efficient frontier) and three optimal portfolios — minimum-variance, maximum-Sharpe (tangency), and risk-parity — versus the equal-weight baseline, long-only and fully invested.
Does Sentinel use machine learning to actually make decisions, or just to describe data? Both, but the emphasis is on decisions. The supervised stress-day classifier labels each day by whether a >5% drawdown follows within a month, trains a logistic-regression and random-forest on volatility/drawdown/momentum features, and is evaluated out-of-sample with a chronological split, time-series cross-validation and ROC-AUC. That prediction then drives a walk-forward tactical backtest: at every monthly rebalance the model is retrained on history-to-date and, when stress probability is high, the portfolio is switched into the minimum-variance allocation. The honest, two-sided finding — gating a concentrated max-Sharpe book cuts its worst drawdown from −42% to −28%, while gating an already-diversified 1/N book does not help (the classic "1/N is hard to beat" result) — is reported as-is.
What is the semi-supervised anomaly detection in Sentinel? Beyond the unsupervised IsolationForest + autoencoder detectors, Sentinel runs label propagation (scikit-learn LabelSpreading over a K-nearest-neighbours graph of trading days), seeded with the high-conviction days both detectors agreed on. It spreads those labels through feature space to surface near-miss days — ones that look just like confirmed anomalies but slipped under a detector's threshold — most usefully the days where the two detectors disagreed.
What are "analog days"? A K-nearest-neighbours retrieval of the historical trading days most similar to today (by the same volatility/drawdown/momentum features the classifier uses), each paired with the market return that actually followed. It answers, without any distributional assumption, "when markets last looked like this, what happened next?" — and is exposed as an agent tool.
What is covariance denoising / Marchenko-Pastur, and why does it matter? A sample covariance matrix estimated from limited history carries measurement noise with a known random-matrix spectrum. Sentinel keeps only the eigenvalues above the Marchenko-Pastur cutoff (signal: the market and sector factors) and flattens the rest, then feeds the cleaned matrix to the Markowitz optimizer. Out-of-sample, minimum-variance weights built on the denoised covariance realize lower volatility than those built on the raw estimate.
Which machine-learning techniques does Sentinel demonstrate? Supervised learning (logistic regression, random-forest ensemble, optional gradient boosting), unsupervised learning (IsolationForest, PCA, KMeans), semi-supervised learning (label propagation), deep learning (a PyTorch autoencoder), and instance-based learning (KNN analog retrieval) — each applied to a concrete quantitative-finance task rather than a toy dataset.
How is tail risk measured? Three ways: historical VaR (empirical quantile), Cornish-Fisher modified VaR (adjusted for skewness and excess kurtosis), and Expected Shortfall (mean loss beyond VaR). The VaR model is then backtested out-of-sample with Kupiec's proportion-of-failures test.
What data sources does Sentinel use, and are they free? All free, no paid keys: Yahoo Finance (via yfinance) for prices, SEC EDGAR's XBRL companyfacts API for 10-K financial statements, and the Ken French Data Library for Fama-French factor returns.
Can I use it with my own portfolio?
Yes — set SENTINEL_TICKERS in .env to any list of Yahoo Finance symbols.
Every layer adapts to whatever returns matrix and set of filings come out of the
warehouse.
Quantitative risk management · Value-at-Risk · Expected Shortfall · Fama-French factor model · factor-adjusted alpha · Markowitz portfolio optimization · efficient frontier · CAPM · Sharpe ratio · forensic accounting · Altman Z-score · Beneish M-score · Piotroski F-score · Benford's Law · DuPont analysis · financial statement analysis · SEC EDGAR · machine learning anomaly detection · autoencoder · supervised classification · logistic regression · random forest · gradient boosting · semi-supervised learning · label propagation · PCA · KMeans clustering · Marchenko-Pastur covariance denoising · KNN analog days · walk-forward backtest · tactical asset allocation · regime detection · Merton distance-to-default · LLM agent · tool use · Python · FastAPI · Streamlit.
Python 3.11+ · pandas · NumPy · SciPy · yfinance · SEC EDGAR · Fama-French / Ken French Data Library · DuckDB · scikit-learn · PyTorch · NetworkX · Anthropic API (claude-opus-4-8) · FastAPI · Docker · Streamlit · Plotly · Next.js · Tailwind · framer-motion

