An offline portfolio analytics workbench with a mean-variance rebalancing engine and a chat layer that is structurally incapable of inventing a number.
22
deterministic tools
0
numbers from the model
3.5%
hard volatility cap
155
tests passing
The problem
A portfolio manager runs performance attribution and rebalancing by hand in a
spreadsheet: recomputing Sharpe and drawdown every month, re-solving allocations under a
volatility ceiling, and answering "how did we do?" from memory. It is slow, easy to fumble,
and there is no permanent record of what changed or why. The obvious modern fix, hand the
numbers to a language model, is exactly the wrong one: an LLM will produce a fluent,
confident, wrong Sharpe ratio, and on client money that is worse than no answer.
What it is
An offline analytics workbench with three parts: an attribution engine,
a mean-variance rebalancing engine with a hard volatility cap, and a chat
assistant. The defining constraint is that the language model cannot compute anything.
It may only choose which deterministic tool to call; every figure in every answer comes out of
plain, tested Python. The model decides what to ask and explains what came back.
How it works
The chat runs on a local GPU model through a LangGraph loop:
recall → model → tool → reason → remember. A test pins the invariant, if any number
ever reaches the user without passing through a tool, the suite fails.
What it removed
Manual
Monthly attribution done by hand in Excel is now one upload. Total/annualised return, volatility, drawdown, Sharpe and Sortino compute in seconds.
Fabrication
The class of error where an AI invents a plausible financial figure is designed out, not merely discouraged. The model routes; it never calculates.
Silence
Bad input raises a typed error the UI shows and the agent returns as structured data. Nothing degrades quietly, which on financial data is the dangerous failure.
Honest limitations
The golden test fixtures are regression baselines, not an independent oracle, they catch drift, they do not prove the metric definitions are correct against an outside reference.
The chat needs a local GPU running Ollama (qwen3:14b). Without it the analytics tabs work fully, but the natural-language layer is unavailable, as shown above.
The full test suite takes ~22 minutes because a soak test cycles the whole pipeline hundreds of times; the fast gate is ~35 seconds.
The public build runs on a synthetic 12-fund universe so the exact-match Excel validation that motivated the design cannot be shown with real data.