Calculate the weights of the portfolio of the Toolkit’s assets that follows the benchmark most closely: the fully invested portfolio with the lowest tracking error, the volatility of its return minus the benchmark’s. With the objective “information_ratio” it is instead the portfolio with the highest information ratio, the expected return above the benchmark per unit of tracking error, which is what an active manager measured against the benchmark maximizes.

The tracking error is TE(w) = √Var(R w - r_b) = √(w’Σ_AA w - 2 w’Σ_Ab + σ_b²), with Σ_AA the annualized covariance matrix of the assets, Σ_Ab their covariances with the benchmark and σ_b² the benchmark’s variance. The information ratio is (w’μ - μ_b) / TE(w), with μ and μ_b the annualized expected returns. The weights sum to one and lie between the minimum and maximum weight; the benchmark is the Toolkit’s (SPY by default) and is not one of the assets.

For more information, see the following papers:

  • Roll, R. (1992). “A Mean/Variance Analysis of Tracking Error.” The Journal of Portfolio Management, 18(4), 13-22.
  • Jorion, P. (2003). “Portfolio Optimization with Tracking-Error Constraints.” Financial Analysts Journal, 59(5), 70-82.
  • Grinold, R.C. and Kahn, R.N. (2000). “Active Portfolio Management.” 2nd edition, McGraw-Hill.

Also known as: index tracking, benchmark tracking, minimum active risk, maximum information ratio portfolio.

Minimum Tracking Error in Python or via the MCP

Install the Finance Toolkit with:

pip install financetoolkit -U

Then call get_minimum_tracking_error_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_minimum_tracking_error_weights()[
    ["Weight", "Expected Return", "Active Return", "Tracking Error", "Information Ratio"]
]

Or, after setting up the Finance Toolkit MCP, ask:

Which weights in Apple, Microsoft, Johnson & Johnson and ExxonMobil tracked the S&P 500 most closely, based on 2021 to 2025?

Which returns:

  Weight Expected Return Active Return Tracking Error Information Ratio
AAPL 0.249 0.1933 0.0411 0.1861 0.2209
MSFT 0.3641 0.2017 0.0495 0.1693 0.2923
JNJ 0.2149 0.0984 -0.0538 0.2113 -0.2545
XOM 0.172 0.291 0.1388 0.2658 0.5224
Portfolio 1 0.1928 0.0406 0.0881 0.4603

Parameters

get_minimum_tracking_error_weights accepts the following parameters.

ParameterTypeDescriptionExample
objectivestr“tracking_error” for the lowest tracking error or “information_ratio” for the highest information ratio. Defaults to “tracking_error”."tracking_error"
periodstrThe frequency of the returns (daily, weekly, monthly, quarterly or yearly). Defaults to “daily”."weekly"
covariancestrThe estimator of the covariance matrix of the assets and the benchmark: “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_spanintThe span in periods of the “exponential” covariance; the weight of a period halves after about span / 2.9 periods. Defaults to 180.180
expected_returnsstrThe estimator of the expected returns: “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_spanintThe span in periods of the “exponential” expected returns. Defaults to 180.180
minimum_weightfloat | 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_weightfloat | 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_boundsdict[str, tuple[float, float]] | NoneThe 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_boundsdict[str, tuple[float, float]] | NoneThe 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_exposurefloatThe sum of the weights: 1 for a fully invested portfolio, 0 for a market neutral one (which needs a negative minimum_weight). Defaults to 1.1
gross_exposurefloat | NoneThe 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_weightsdict[str, float] | NoneThe 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 or transaction cost needs them.None, which uses the latest weights of the Portfolio the Toolkit came from when a maximum turnover or transaction cost needs them
maximum_turnoverfloat | NoneThe 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
roundingint | NoneThe number of decimals to round the results to. Defaults to None, which uses the Toolkit’s rounding.2
Share