← projects

[Living Frontier]

Macro-Aware Portfolio Optimizer

A broken Markowitz spreadsheet rebuilt as a tested Python system that knows the macro regime.

● EvolvingQuant & ResearchPersonalPythonNumPySciPyscikit-learnChromaDB
01 /context

It started as an Excel portfolio calculator: Sharpe ranking, Markowitz weights, a Monte Carlo frontier. Part of it showed #NUM! and #DIV/0!, and the Monte Carlo had never run.

02 /my role

Solo: the port to Python, the macro layer, the event-study database and validation.

03 /problem

Even when it worked, the spreadsheet allocated as if the economy didn't exist: weights came only from past returns, whatever the rate cycle.

04 /how it works
  1. 01 · Port first, bugs documented

    Each spreadsheet tab became a module (data, returns, ranking, optimizer, frontier, evaluation). Its bugs were written down and fixed, not copied. Prices come from a market-data API instead of pasted tables.

  2. 02 · Regime classifier

    Central-bank bias (hawkish / neutral / dovish) × growth (expansion / contraction), from rate decisions, inflation and GDP. A level override reads cuts from a restrictive rate (above 10% in Brazil, 3.5% in the US) as normalization, not easing.

  3. 03 · Event study → macro alpha

    Past macro events with asset reactions at T+1, T+5 and T+20 are embedded (MiniLM) into a local vector DB. Similar events adjust expected returns, dampened to 30% of the historical move and clipped per day.

  4. 04 · Constraints by regime

    Each regime sets caps and floors per asset class — more bonds and less crypto when policy is tight — then SLSQP maximizes Sharpe.

  5. 05 · A frontier that reaches the crest

    Monte Carlo mixes uniform Dirichlet, sparse Dirichlet(0.3) and convex blends toward the optimum, so the cloud actually touches the frontier.

  6. 06 · Crypto handled apart

    Short histories make sample covariance unstable, so crypto uses Ledoit-Wolf shrinkage and risk parity with a cap, tilted by the macro signal.

05 /architecture
01
Prices
02
Returns & Sharpe
03
Regime classifier
04
Event-study DB (vectors)
05
Regime constraints
06
SLSQP max-Sharpe
07
Monte Carlo frontier
08
JSON export
06 /interactive demos

Efficient Frontier Playground

what you're seeing

Each dot is a random portfolio: risk on the x axis, expected return on the y axis, color by Sharpe ratio. The ringed dot is the best Sharpe; on the right, its weights. The regime buttons apply each regime's caps per asset class.

try this

  1. 1.Turn sparse sampling off and on — without it, the cloud never reaches the upper edge.
  2. 2.Switch from a dovish to a hawkish regime and watch crypto and equities shrink.
  3. 3.Lower the number of simulations to see how noisy the optimum gets.

real vs simplified

Sampling is the real method (uniform Dirichlet, sparse Dirichlet 0.3 and blends toward the optimum). Assets, returns and caps are synthetic, and the real system finds the optimum with SLSQP instead of picking the best sample.
[lab] loading demo…

Macro Regime Classifier

what you're seeing

The sliders set the central bank's bias, growth and the policy-rate level; the grid shows the resulting regime and its constraints. Below, a past event's reaction per asset class at T+1, T+5 and T+20, and how much of it becomes an adjustment to expected returns.

try this

  1. 1.Push the bias to dovish, then raise the rate above 10%: the override reads the cut as normalization (neutral).
  2. 2.Pick each event and compare the raw reaction with the final adjustment.
  3. 3.Notice the clip: a big reaction never moves expected returns by more than the cap.

real vs simplified

The rules are the real ones (10% floor for Brazil's policy rate, 30% dampening, clipping). Events, reactions and asset classes are fictional; the real system finds similar past events by vector search.
[lab] loading demo…
07 /results
209 automated tests.
Out-of-sample walk-forward validation of the weights.
A JSON contract consumed by the agent runner and the research terminal.
08 /what broke and what I changed
  • ! brokePlain Dirichlet samples clustered in the middle of the cloud and never reached the frontier's crest.

    → changedSparse samples plus convex blends toward the optimum.

  • ! brokeCuts from very high rates were classified as dovish and loosened the risk limits too early.

    → changedThe level override.

  • ! brokeAssets with short histories made SLSQP fail to converge.

    → changedLedoit-Wolf covariance and risk parity for that universe.

09 /related