A Wealth Tax Is a Silent Partner

wealth tax
portfolio theory
asset pricing
The surprising mathematics of proportional wealth taxation — and why your optimal portfolio doesn’t change.
Author

Anders G Frøseth

Published

February 15, 2026

The intuition

Imagine you own a portfolio of stocks, bonds, and other assets. The government introduces a 1% annual wealth tax on the market value of everything you own. Your first instinct might be to restructure your portfolio — perhaps shift toward safer assets, or toward asset classes that are harder to value.

But here’s the surprising result: under a cleanly implemented proportional wealth tax, your optimal portfolio doesn’t change at all.

The mathematics

The result depends on three conditions: the tax is levied at a uniform rate on all assets, assessed at market value, in frictionless markets (no transaction costs from liquidating to pay the tax). Under these conditions, the tax enters as a single multiplicative factor that scales the entire portfolio identically — which is what drives the neutrality. Relax any one of them and the clean factorisation breaks.

Consider a single-period setting. An investor holds a portfolio with random gross return \(R\). Without the wealth tax, terminal wealth is

\[ W_1 = W_0 \cdot R \]

With a proportional wealth tax at rate \(\tau\), the tax is levied on the market value of the portfolio at the end of the period, so terminal wealth after tax becomes

\[ W_1^\tau = W_0 (1 - \tau) \cdot R \]

The key observation is that \((1 - \tau)\) is a multiplicative constant — it scales all outcomes by the same factor. This means:

  • Expected wealth falls by the factor \((1 - \tau)\)
  • Standard deviation of wealth also falls by exactly \((1 - \tau)\)
  • The coefficient of variation \(\sigma / \mu\) is unchanged
  • The Sharpe ratio of every portfolio is preserved

In the mean–standard deviation plane, the wealth tax induces a homothetic contraction of the entire opportunity set toward the origin. Every frontier portfolio shrinks proportionally, so the tangency portfolio — the one with the highest Sharpe ratio — remains the same.

A visual example

Here’s what this looks like for a simple two-asset portfolio. We can compute the efficient frontier with and without the tax:

Code
import numpy as np
import matplotlib.pyplot as plt

# Parameters
rf = 0.04           # risk-free rate
tau = 0.15          # illustrative tax rate (as in Paper 1, Figure 3)

# Two risky assets
er = np.array([0.07, 0.14])          # expected returns
vol = np.array([0.10, 0.22])         # volatilities
rho = 0.25                            # correlation
cov = np.array([[vol[0]**2, rho*vol[0]*vol[1]],
                [rho*vol[0]*vol[1], vol[1]**2]])

# Efficient frontier (parametric in weight w on asset 1)
w1 = np.linspace(-0.3, 1.2, 500)
port_er = w1 * er[0] + (1 - w1) * er[1]
port_vol = np.sqrt(w1**2*cov[0,0] + (1-w1)**2*cov[1,1]
                    + 2*w1*(1-w1)*cov[0,1])

# Upper branch: keep only the part above the minimum-variance portfolio
min_idx = np.argmin(port_vol)
front_vol = port_vol[:min_idx+1][::-1]     # reverse so sigma increases
front_er  = port_er[:min_idx+1][::-1]

# Tangency portfolio (analytic)
excess = er - rf
cov_inv = np.linalg.inv(cov)
w_tan = cov_inv @ excess
w_tan = w_tan / w_tan.sum()
sigma_tan = np.sqrt(w_tan @ cov @ w_tan)
mu_tan    = w_tan @ er
sharpe    = (mu_tan - rf) / sigma_tan       # slope of the CAL

# After-tax tangency (homothetic contraction)
sigma_tan_tax = (1 - tau) * sigma_tan
mu_tan_tax    = (1 - tau) * (1 + mu_tan)    # gross return

# Plot
fig, ax = plt.subplots(figsize=(8, 5.5))

# Pre-tax frontier (in gross-return space)
ax.plot(front_vol, 1 + front_er, color='#1a4a7a', linewidth=2,
        label='Pre-tax frontier')

# After-tax frontier: homothetic contraction by (1 - tau)
ax.plot((1-tau)*front_vol, (1-tau)*(1+front_er), color='#a31f34',
        linewidth=2, linestyle='--',
        label=f'After-tax frontier ($\\tau$ = {tau:.0%})')

# Capital allocation lines (tangent by construction)
cal_sigma = np.linspace(0, max(front_vol)*1.05, 100)
cal_pretax   = (1 + rf)             + sharpe * cal_sigma
cal_aftertax = (1 - tau) * (1 + rf) + sharpe * cal_sigma

ax.plot(cal_sigma, cal_pretax, color='#1a4a7a', linewidth=0.8, alpha=0.6)
# Trim after-tax CAL near its tangency point
mask_cal = cal_sigma <= sigma_tan_tax + 0.06
ax.plot(cal_sigma[mask_cal], cal_aftertax[mask_cal], color='#a31f34',
        linewidth=0.8, alpha=0.6, linestyle='--')

# Risk-free points
ax.plot(0, 1 + rf, 'o', color='#1a4a7a', markersize=6, zorder=5)
ax.plot(0, (1 - tau) * (1 + rf), 'o', color='#a31f34', markersize=6,
        zorder=5)
ax.text(0.008, 1 + rf, '$1+r_f$', fontsize=9, color='#1a4a7a',
        ha='left', va='top')
ax.text(0.008, (1 - tau) * (1 + rf),
        '$(1{-}\\tau)(1{+}r_f)$', fontsize=9,
        color='#a31f34', ha='left', va='top')

# Tangency points
ax.plot(sigma_tan, 1 + mu_tan, 'o', color='#1a4a7a', markersize=8,
        zorder=5)
ax.plot(sigma_tan_tax, mu_tan_tax, 'o', color='#a31f34', markersize=8,
        zorder=5)
ax.text(sigma_tan + 0.008, 1 + mu_tan + 0.012, '$T$', fontsize=11,
        color='#1a4a7a', fontweight='bold')
ax.text(sigma_tan_tax - 0.018, mu_tan_tax + 0.012, "$T'$", fontsize=11,
        color='#a31f34', fontweight='bold', ha='right')

# Dotted ray from origin through tangency points
ray_end_sigma = sigma_tan * 1.15
ray_end_mu    = ((1 + mu_tan) / sigma_tan) * ray_end_sigma
ax.plot([0, ray_end_sigma], [0, ray_end_mu], ':', color='gray',
        linewidth=0.8)

# Arrow showing radial contraction
ax.annotate('', xy=(sigma_tan_tax + 0.002, mu_tan_tax + 0.012),
            xytext=(sigma_tan - 0.002, 1 + mu_tan - 0.012),
            arrowprops=dict(arrowstyle='->', color='#4a4a4a', lw=1.5))
ax.text(sigma_tan + 0.008, (1 + mu_tan + mu_tan_tax) / 2,
        '$(1{-}\\tau)$', fontsize=10, color='#4a4a4a')

# Dotted vertical at sigma*
ax.plot([sigma_tan, sigma_tan], [0.7, 1 + mu_tan], ':', color='gray',
        linewidth=0.8)
ax.text(sigma_tan, 0.69, '$\\sigma^*$', fontsize=9, color='gray',
        ha='center', va='top')

ax.set_xlabel('Portfolio volatility $\\sigma$', fontsize=11)
ax.set_ylabel('Expected gross return $1 + \\mu$', fontsize=11)
ax.set_title('Homothetic contraction under wealth tax',
             fontsize=12, fontweight='bold')
ax.legend(fontsize=9, frameon=False, loc='upper left')
ax.set_xlim(-0.01, 0.32)
ax.set_ylim(0.7, 1.25)
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.grid(True, alpha=0.15)

plt.tight_layout()
plt.show()
Figure 1: Homothetic contraction of the efficient frontier under a wealth tax. In the gross-return plane, the tax contracts the entire opportunity set radially toward the origin by the factor \((1-\tau)\). The tangency portfolio \(T\) moves to \(T'\) along the ray from the origin — both risk and return shrink proportionally, so the Sharpe ratio is preserved. The tax rate is set to 15% for visual clarity; the geometry is identical at any rate.

The tangency portfolio weight \(w^*\) is identical in both cases — the tax doesn’t change which portfolio is optimal. It only changes how much wealth you end up with.

The silent partner analogy

The wealth tax is mathematically equivalent to the government becoming a silent partner in your portfolio. Each year, the state claims a \(\tau\) fraction of your holdings — as if it owns \(\tau\) percent of every share you hold. Your return per share is unaffected; you simply hold fewer shares after the tax.

This is the core insight of the neutrality framework.

When does this break down?

In practice, wealth taxes are never this clean. The seven channels of distortion identified in the framework show exactly how and why real wealth taxes depart from neutrality — from non-uniform assessment fractions to the amplification effects of inelastic markets.

The neutrality result is not an argument for or against wealth taxes. It is a benchmark — a precisely defined starting point from which to measure the actual distortions introduced by any specific implementation.