Resampled Efficient Frontier
Calculate the weights of the resampled efficient portfolio (Michaud resampling): the average of the optimal weights over many return histories that could have been observed instead of the actual one. A single optimization takes the estimated expected returns and covariances at face value and piles into the assets whose estimates happen to be highest; averaging over resampled histories only gives an asset a large weight when it earns it in most of them, which makes the weights more diversified and more stable from one estimate to the next.
Every draw has as many periods as the returns. With “parametric” resampling, as in Michaud, the draws come from a multivariate normal distribution with the estimated expected returns and covariance; with “bootstrap” they are periods of the actual returns drawn with replacement, which keeps their fat tails and skew. The objective is optimized on the sample mean and sample covariance of every draw within the constraints, and the weights are averaged.
For more information, see the following sources:
- Michaud, R. O. (1998). “Efficient Asset Management: A Practical Guide to Stock Portfolio Optimization and Asset Allocation.” Harvard Business School Press.
- Scherer, B. (2002). “Portfolio Resampling: Review and Critique.” Financial Analysts Journal, 58(6), 98-109.
Also known as: Michaud resampling, resampled efficiency, resampled efficient frontier, portfolio resampling.
Resampled Efficient Frontier in Python or via the MCP
Install the Finance Toolkit with:
pip install financetoolkit -U
Then call get_resampled_efficient_weights as shown below.
from financetoolkit import Toolkit
toolkit = Toolkit(
["AAPL", "MSFT", "JNJ", "XOM"],
api_key="FINANCIAL_MODELING_PREP_KEY",
start_date="2021-01-01",
end_date="2025-12-31",
)
toolkit.portfolio.get_resampled_efficient_weights()[
["Weight", "Expected Return", "Volatility", "Sharpe Ratio", "Weight Standard Deviation"]
]
Or, after setting up the Finance Toolkit MCP, ask:
Which weights in Apple, Microsoft, Johnson & Johnson and ExxonMobil does a resampled efficient frontier give, based on 2021 to 2025, and how much does each weight vary across the resamples?
Which returns:
| Weight | Expected Return | Volatility | Sharpe Ratio | Weight Standard Deviation | |
|---|---|---|---|---|---|
| AAPL | 0.097 | 0.1932 | 0.2786 | 0.5725 | 0.1559 |
| MSFT | 0.2598 | 0.2017 | 0.2571 | 0.6534 | 0.212 |
| JNJ | 0.2171 | 0.0987 | 0.1673 | 0.3884 | 0.2159 |
| XOM | 0.4261 | 0.2911 | 0.2702 | 0.9524 | 0.2297 |
| Portfolio | 1 | 0.2166 | 0.1622 | 1.1273 | nan |
Parameters
get_resampled_efficient_weights accepts the following parameters.
| Parameter | Type | Description | Example |
|---|---|---|---|
objective | str | The portfolio optimized in every draw: “maximum_sharpe”, “minimum_variance” or “mean_variance” (with the risk aversion). Defaults to “maximum_sharpe”. | "maximum_sharpe" |
resamples | int | The number of resampled return histories. The average settles as their number grows; 500 keeps the weights within about a percentage point of their limit for a handful of assets. Defaults to 500. | 500 |
resampling | str | How the histories are drawn: “parametric” (a multivariate normal distribution with the estimated expected returns and covariance) or “bootstrap” (the actual periods, drawn with replacement). Defaults to “parametric”. | "parametric" |
seed | int | None | The seed of the random draws; the same seed gives the same weights. Defaults to 0; None draws anew on every call. | 42 |
risk_aversion | float | The risk aversion of the “mean_variance” objective. Defaults to 2.5. | 2.5 |
period | str | The frequency of the returns (daily, weekly, monthly, quarterly or yearly). Defaults to “daily”. | "weekly" |
covariance | str | The estimator of the covariance matrix the “parametric” draws come from and the table reports: “sample” (ddof=1), “ledoit_wolf” (towards the scaled identity, Ledoit and Wolf, 2004), “ledoit_wolf_constant_correlation” (towards the average correlation, Ledoit and Wolf, 2004), “ledoit_wolf_single_factor” (towards the covariance that the benchmark as a single factor implies, Ledoit and Wolf, 2003), “oas” (Chen et al., 2010), “semicovariance” (the co-movement below a zero return, Estrada, 2007), “exponential” (recent periods weigh most, RiskMetrics) or “denoised” (the eigenvalues of the correlation matrix that random returns could produce averaged, Laloux et al., 2000). Defaults to “sample”. | "sample" |
covariance_span | int | The span in periods of the “exponential” covariance; the weight of a period halves after about span / 2.9 periods. Defaults to 180. | 180 |
expected_returns | str | The estimator of the expected returns the “parametric” draws are centred on: “mean” (the historical average), “exponential” (the exponentially weighted average, recent periods weigh most), “capm” (the returns the Capital Asset Pricing Model implies from each asset’s beta to the benchmark, Sharpe, 1964) or “james_stein” (the averages shrunk towards that of the minimum variance portfolio, Jorion, 1986). Defaults to “mean”. | "mean" |
expected_returns_span | int | The span in periods of the “exponential” expected returns. Defaults to 180. | 180 |
minimum_weight | float | dict[str, float] | The lowest weight of every asset, or per asset, e.g. {“AAPL”: 0.05} (the others keep 0); a negative value allows short positions. Defaults to 0. | 0 |
maximum_weight | float | dict[str, float] | The highest weight of every asset, or per asset, e.g. {“AAPL”: 0.3} (the others keep 1). Defaults to 1. | 1 |
sector_bounds | dict[str, tuple[float, float]] | None | The minimum and maximum total weight per sector, e.g. {“Technology”: (0, 0.4)}, with the sector of each asset from its company profile. Defaults to None. | None |
country_bounds | dict[str, tuple[float, float]] | None | The minimum and maximum total weight per country, named in full or by its two-letter code, e.g. {“United States”: (0, 0.6)}, with the country of each asset from its company profile. Defaults to None. | None |
net_exposure | float | The sum of the weights: 1 for a fully invested portfolio, 0 for a market neutral one. Defaults to 1. | 1 |
gross_exposure | float | None | The highest sum of the absolute weights, which limits the leverage of a long-short portfolio, e.g. 1.6 for a 130/30 portfolio. Defaults to None, no limit. | None, no limit |
current_weights | dict[str, float] | None | The weights held now, e.g. {“AAPL”: 0.5, “MSFT”: 0.5} (an asset left out is not held), which the turnover is measured from; they add a Turnover column, |w_i - w0_i| per asset and its sum for the portfolio. Defaults to None, which uses the latest weights of the Portfolio the Toolkit came from when a maximum turnover needs them. | None, which uses the latest weights of the Portfolio the Toolkit came from when a maximum turnover needs them |
maximum_turnover | float | None | The highest turnover Σ |w_i - w0_i| from the current weights, e.g. 0.2 to trade at most 10% of the portfolio each way. Defaults to None, no limit. | None, no limit |
include_benchmark | bool | Whether to include the benchmark as an asset. Defaults to False. | True |
rounding | int | None | The number of decimals to round the results to. Defaults to None, which uses the Toolkit’s rounding. | 2 |