'Formula Weight' Position Sizing Method

Hi guys,
You should have a closer look at the Position Weight Formula.


What a great chart, Georg! Thanks!

What do you think about rebalancing based on inverted mktcap versus including mktcap (lower is better) into the ranking system? I think I’m going to experiment with this.

An analysis in The Case For Reverse-Cap-Weighted Indexing provides support for weighting the stocks of the S&P 500 Index inversely to their market capitalization (MktCap) in order to achieve higher returns than the index.
https://seekingalpha.com/article/4122258-case-reverse-cap-weighted-indexing

There is also a new ETF RVRS following this index.

• For the 19 year period the cap-weighted portfolio showed an annualized return of 6.62% with a maximum drawdown of -54%.
• An equal-weighted portfolio would have had an annualized return of 10.27% with a maximum drawdown of -59%.
• A reverse-cap-weighted portfolio would have had an annualized return of 13.22% with a maximum drawdown of -65%.
• The higher return of the reverse-cap-weighted portfolio is attributed to the higher average returns of the smaller cap stocks relative to the larger cap stocks of the S&P 500.

Thanks for the paper, Georg. I was wonder what exactly Reverse-Cap meant.

Walter

Thank you Georg - very interesting. Seems to confirm that smaller caps perform better over time (even if the small caps here are still quite large!)
I must say I could sense the potential but have not had the time to look into how to use the formula Weight.

I just read the tutorial which is helpful albeit limited (in my view). More examples of practical use would be welcomed in it

To test your suggestion on my existing systems - am I correct if I do (this would be my first attempt at using formula weight):

  1. create a custom series that outputs the min mktcap of the universe (here SP500) → call it MinMktCap
  2. create another custom series that outputs the max mktcap of the universe (here SP500) → MaxMktCap
  3. add in the field “Position Weight Formula” → close(0, getseries(“MinMktCap”)) + ( close(0, getseries(“MaxMktCap”)) - Mktcap )

NB: not looking for any special sauce you might have added - just plain vanilla “reverse” mktcap as can be computed on P123

Many thanks

Jerome

Jerome,
It is not as complicated as that.
In the formula box write 1/MktCap fro a reverse-cap-weighted model, MktCap for a cap-weight model, and 1 for an equal weight model.

Ah! Thanks Georg.

Using 1/MktCap, I do get a similar general outcome on the SP500 (a promising likely improvement on existing models for min effort) but still significantly different from yours:

  • Are there further settings in the formula weight area that I need to better understand / become familiar with?
  • To keep things simple I put transaction & slippage at zero and price = next open. I still get a different curve from yours when making that more real (eg variable slippage, my real transaction costs on IB and middle Hi-Lo)

Public sim here → https://www.portfolio123.com/port_summary.jsp?portid=1516760

Thanks

Jerome

Now with a cap-weighted model, you never need to rebalance. As a stock grows in market cap, it takes up more space in your portfolio.

With a reverse-market-cap weighted model, you have to rebalance the hell out of it in order to keep it running. Does your chart take into account the transaction costs of doing so? And how often does it rebalance?

Jerome,
I used next close, and rebalance daily. All transaction costs set to zero and starting capital 1,000,000. The idea of the charts is to compare the index for various weighting systems, not to trade it. If you want to invest in a reverse-cap-weighted ETF then use RVRS, and for equal-weight use RSP.

You may want to set starting capital even higher to get all 500 stocks into the model.

Yuval,
You can build low turnover model with more sophisticated rev-weighted formula.


RVRS rebalances quarterly. They often have to sell their biggest positions, as the lowest-cap stocks drift out of the S&P 500 and get replaced by other stocks. This leads to poor tracking and forced capital gains payouts. The expense ratio is 0.29%, which is three times that of SPY’s, and that’s in a very low-volatility environment; doubtless that expense is going to go up when market volatility goes back to normal.

If you rebalance quarterly and take transaction and cap gain costs into account, what would your chart look like then? Would RVRS really outperform SPY?

Hi! Would anyone be able to share some more sophisticated position sizing formula ideas and settings which either incorporate min/max levels already in the formula (instead of setting it manually based on the # of holdings), control turnover or extreme differences between largest and smallest positions?

I think a while ago I saw usage of log function or something like 100+ Rank() etc. I have only briefly tested the formula weight rebalancing, but so far have been disappointed with the results because alternative rebalancing formulas have either increased concentration or the turnover often mostly outweighed any benefits. Also I find it really complicated and there are so many moving parts (settings) that it is hard to understand where improvements/costs come from.

This is what I do. The rebalance formula I use is

min(eval(rankpos<91,91-rankpos,1)0.5(1-$spred/$mmdt1000000+$trcost),908.32*$mmdt/535000)

where $spred is a custom formula estimating the bid-ask spread as a percentage of price, $trcost is a custom formula estimating the transaction cost as a function of price and volume (and comes up with a number between 0.75 and 1), and $mmdt is a custom formula for minimum median daily dollar volume over various time periods. The first part of the formula is a simple ranking formula; the second part adjusts that lower for stocks with high spreads or high transaction costs. The 535000 is the amount of money I have to invest, and the 8.32 is inverse of the maximum permissable percentage of one of my holdings, so the last part of the formula basically says that I can’t own more than 50% of the $mmdt of a stock.


Hi Yuval, thanks for the example. I’m curious - if I’m interpreting right, assuming there is sufficient liquidity you’re putting about 2% into each of your top rated stocks and gradually sliding down to 1% by your 50th position, and almost down to nothing at the bottom (picks 70-90 would be about 5% of the portfolio). Please correct me if I’m wrong. I’m wondering if you could share your thought on why you shaped your weighting scale this way? What advantages do you see from extending the list that deeply? thanks in advance. :wink:

This model has a buy rule of rankpos <= 17 so the number of positions varies from 30 to 35. Because of the way the rebalancing system works, the stocks with the highest ranks are bought at about 5% of the portfolio, while those with the lowest ranks have less than 0.25%. When you limit the number of positions with a buy rule, the “ideal number of positions” can be 50 or 500 and the simulation will be almost exactly the same. That’s assuming you put “Yes” in the “use margin” box in the “General” tab, which I always do when using formula weight rebalancing.

I use this to TEST my ranking systems. My actual buying and selling system is about half of this: I use 40 rather than 90 as my upper limit, 9 rather than 17 as my rankpos buy rule, and 12% rather than 5% as my maximum position.

Thanks for the discussion Yuval, esp around the max position targets. I had just mocked something up in Excel and was misunderstanding how you were applying the rule. I think I saw the 91 in the calc and started “assuming” ;-). The 12% max position size actually surprises me. Thanks for sharing your thoughts.

Thank you so much, Yuval, for sharing this.

This is really interesting! I am sure with such a concept like yours in mind I will hopefully come up with something that can improve my results a bit.

Also it is a great idea of controlling positions via buy rules and to turn on margin.

Some more follow up questions:

  1. obviously it depends, but what kind of increase in returns are to expect from the intro of the formula-based weighting? 10%? Bringing a port from 25 to 28% p.a.? I would be very happy to hear your experience
  2. after the initial concept generation, what are you guys typically focussing on next of all the settings that exist in formula-based weighting?
  1. A modest increase of 2 to 8 percent is a reasonable expectation. The return you’ll get by enabling margin will be much higher than that, so you have to adjust that to what the return would have been without margin. Here’s the formula. In Excel, if your total equity is in column F and your leverage is in column G, to get your actual returns in column H you’d put $1.00 in the first cell (cell 2), =H2*((F3/F2-1)/G3+1) in cell 3, =H3*((F4/F3-1)/G3+1) in cell 4 and just copy that one down the column (notice cell 4 is different from cell 3 because you can’t use G2 in cell 3 (it’s usually 0)). So, for example, in one simulation I did my total equity increased from $10,000 to $352 million over 18 years for a CAGR of 78.88%. My leverage varied from 0.73 to 1.40 during this period. My adjusted return on $10,000 would have been only $118 million, for a CAGR of 68.33%. That’s the only way to make a margin-based simulation comparable to one done without margin. The reason I use margin is that if you run the simulation without margin and you look at the transaction records, the buys are all over the map depending on how much you’re selling. But if you use margin, your buys are consistent with the formula you input.

  2. The settings I typically focus on the most are the rebalancing equation, the buy and sell rules, the maximum and minimum positions, and the minimum rebalance transaction.

I was able to replicate the formula weighting method in Mathematica using a simple example of weight scheme which depends only on rank position.

For your enjoyment:

(* source: https://www.portfolio123.com/doc/side_help_item.jsp?id=62 *)

Print["Weight formula"]
Clear[rankPos]
rankPos = Range[30];
formula =  2^(1*(positions - rankPos)/(positions - 1))

Print["Params"]
params = {positions -> 30, maxConstraint -> .04, 
  minConstraint -> 0.03, hedgeRatio -> 0, Leverage -> 1, 
  maxPortDeviation -> .01}
targetPosExposure = 1 - hedgeRatio /. params

(* Step 1 *)
Print["First,the raw weights are computed from the formula:"]

sum = Total[formula /. params] // N

minWeight = \[Infinity]; maxWeight = -\[Infinity];
x = (formula /. params)/sum
Subscript[pos, IdealWeight] = x;

minWeight = Min[minWeight, x]
maxWeight = Max[maxWeight, x]

(* Step 2 *)
Print["Next,the weights are normalized to the range of the weight \
constraint inputs:"]

s = (maxConstraint - minConstraint)/(maxWeight - minWeight) /. params

Subscript[pos, IdealWeight] = 
 minConstraint + (Subscript[pos, IdealWeight] - minWeight)*s /. params

(* Step 3 *)
Print["Finally,the weights are normalized to the target position \
exposure:"]

pct = 0

pct = Total[Subscript[pos, IdealWeight]]

scaleToward =  
 If[pct > targetPosExposure , minConstraint, maxConstraint] /. params

fromPortWeight = scaleToward*Length[rankPos]

s = (targetPosExposure - fromPortWeight)/(pct - fromPortWeight)

Subscript[pos, IdealWeight] = 
 scaleToward + (Subscript[pos, IdealWeight] - scaleToward)*s

Total[Subscript[pos, IdealWeight]]