I'm trying to build a Capped Index Fund of crypto currencies. As Investopedia explains, a "Capped index is an equity index that has a limit on the weight of any single security. Thus, a capped index sets a maximum percentage on the relative weighting of a component that is determined by its market capitalization. The rationale behind a capped index is to prevent any single security from exerting a disproportionate influence on an index."

I need an algorithm or a spreadsheet that calculates the capped weightings of the currencies. Page 6 of Morningstar Index Calculation Methodology seems to discuss the formulas I need to calculate the capped weightings but I'm having trouble translating these into an code.

As I think about the algorithm needed, it seems some sort of nested or recursive loop would be necessary. Every time the weighting of one currency is capped, the weightings of the remaining currencies need to go up proportionally. Perhaps this could be accomplished by recursively calling the capping algorithm on the remaining currencies with a modified cap for each recursive call. Or maybe I'm confused and over thinking it.

Here's a spreadsheet based on my first attempt to solve this.

Is anyone aware of some sample code or a spreadsheet that accomplishes this? Anyone want to take a crack as some pseudo code?

Many thanks.


I figured it out! See the second tab of my spreadsheet for the solution.

And for what it's worth, here's my Java code. No recursion needed!

final double totalMarketCap = filteredTickers.stream().mapToDouble(ticker -> ticker.getMarketCapUSD().doubleValue()).sum();
double cappedRemaining = 1d;
double marketRemaining = 1d;
for (CoinMarketCapTicker ticker : filteredTickers) {
    double marketPercentage = ticker.getMarketCapUSD().doubleValue() / totalMarketCap;
    double uncappedPercentage = marketPercentage * cappedRemaining / marketRemaining;
    double cappedPercentage = Math.min(uncappedPercentage, _indexCap);

    _indexTickers.add(new IndexTicker(ticker, marketPercentage, cappedPercentage));

    marketRemaining -= marketPercentage;
    cappedRemaining -= cappedPercentage;
  • $\begingroup$ could you please reply with the link to Morningstar Index Calculation Methodology? Link in a questions points me to Morningstar Indexes Website. Thanks $\endgroup$ – user38932 Feb 22 '19 at 23:57
  • $\begingroup$ Hmm. I guess it was removed. You could try an archive site like Wayback Machine. $\endgroup$ – Corey Feb 24 '19 at 0:27
  • $\begingroup$ How would you you calculate the base value of the index? $\endgroup$ – user38932 Feb 27 '19 at 20:47
  • $\begingroup$ You need a source of market caps like CoinMarketCap.com. $\endgroup$ – Corey Mar 1 '19 at 0:48
  • $\begingroup$ here's Edu writing from 2021! I'm interested on the google sheet you made, and update it to create an index for crypto in 2021. Can I get an editable version of the document? I will be much appreciated. my email: eduforte@gmail.com THX so much! $\endgroup$ – Edu Forte Apr 9 at 20:37

I think it can be done iteratively.

For each security you need a boolean variable Capped which is 1 if the security is currently at its cap or 0 otherwise. Initially Capped[i]=0 for all securities i and initially Weight[i]=the market value based weight of security i.

Then you go onto a loop:

You set Finished to TRUE

First you examine all uncapped securities and if Weight[i]> Cap you set Weight[i]=Cap; Capped[i]=1 and Finshed=FALSE

Second you compute the free (or uncapped) weight, which is equal to 1 minus the sum of the weights of the capped securities.

Third for all uncapped securities, you assign them a weight proportional to their market value and such that their sum is equal to the free weight computed in step 2.

If FINSHED=FALSE (meaning that some security was capped in this iteration) you go back to the top of this loop, else you exit this loop.

(A word of warning, however, this pseudo-code has not been debugged).

  • $\begingroup$ Thanks for the suggestion! I think that would work. But I like my solution. :) $\endgroup$ – Corey May 16 '18 at 3:44
