Tax-Aware Direct Indexing
Track a benchmark. Harvest losses lot by lot. Respect wash sales.
Backtest figures will appear here once results on real data are published. Until then, this page sets out the method.
Backtest results are coming soon.
Backtest results on real data will be published with a forthcoming paper on SSRN, a preprint server for research papers. The paper describes the methodology and compares a CPU solver with a GPU solver on real data. Until then, this site explains the method, and the tools show results on sample portfolios.
When they land, this section will chart the strategy's after-tax growth against its benchmark and its drawdowns, with tracking error, turnover and harvested losses alongside.
An index fund holds the index for you as a single position. Direct indexing holds the same stocks directly, so any stock that drops can be sold to bank a tax loss against your other gains, then replaced with a similar stock so the portfolio keeps tracking the index.
| Σ wᵢ = 1 | Fully invested — weights (cash included) sum to 1 |
| wᵢ ≥ 0 | Long-only |
| c_min ≤ w_cash ≤ c_max | Hard cash buffer (0.25–0.5% of NAV) |
| |wᵢ − w_b,ᵢ| ≤ band (soft) | Per-name and per-sector drift is free inside the band, linearly penalized outside it — no hard name cap or tracking-error cap |
Minimize the weighted sum of two things: (i) the portfolio's factor distance from the benchmark, measured under the risk model Σ, and (ii) the tax cost on realized gains, net of the tax saved on realized losses. Both are in the same units: with λ_te = λ_tax = 1, (1% tracking error)² costs as much as 1% of the portfolio's value in tax. The two weights λ_te and λ_tax set the balance: push λ_tax up and the optimizer harvests harder at the cost of wider tracking error; push λ_te up and the portfolio hugs the index more tightly.
In the backtest, this is solved as a portfolio-optimization problem at each rebalance, written in CVXPY (an open-source modelling library) and solved by a CPU-based conic solver. The solver searches the portfolios the constraints allow and returns the weights that minimise the objective. The forthcoming paper on the methodology compares a CPU solver with a GPU solver on real data. Nothing runs on this site: everything is computed offline.
- Holdings + lots
Per-account lot-level positions with acquisition date, cost basis, and quantity.
- Benchmark weights
Target weights from the chosen benchmark index (a broad US or global equity index).
- Prices + risk model
Daily prices and the factor risk model that drives the tracking-error metric.
- Constraints
Cash buffer, soft per-name and per-sector bands, exclusions, and any other customization knobs.
- Trade list
Lot-level buys and sells for the day, each identified by the lot it touches.
- New weight vector
Target weights w* after the solve — what the portfolio should hold tomorrow.
- Realized P/L
Per-lot realized gain/loss for the day, split into short-term and long-term buckets.
Factor tilt
A factor tilt lets the optimizer hold more of the names that score well on a chosen factor — quality, value, momentum, or low-volatility — and less of the names that score poorly. The portfolio still tracks the benchmark, but with a measurable lean toward the chosen factor.
B_f is the column of factor loadings for the chosen factor from the risk model. The constraint forces the portfolio's active exposure to that factor to be at least t_f standard deviations above the benchmark. The optimizer redistributes weight within the tracking-error budget to satisfy it — buying high-scoring names, underweighting low-scoring ones.
You consume part of your tracking-error budget on the tilt. Less budget remains for tax-loss harvesting, so factor tilts typically reduce expected harvest activity slightly. The factor's own active return is the offset.
| Long/Short Tax-Aware | Market-Neutral Pair Sleeve | Tax-Aware Direct Indexing | |
|---|---|---|---|
| Net exposure | 100% | 0% | 100% |
| Factor exposure | Tracked | Pinned to zero | Tracked |
| Source of return | Index + tax + active | Cross-sectional alpha | Index + tax alpha |
| Role | Standalone book | Companion sleeve | Standalone book |