Is there a formula to rebalance investment funds?

JenniferMurphy

Well-known Member
Joined
Jul 23, 2011
Messages
2,707
Office Version
  1. 365
Platform
  1. Windows
Suppose I have 3 index funds as shown in the minisheet below. My investment strategy asks that I try to maintain the 3 funds so that A is 50%, B is 40% and C is 10%. As you can see, A is at 59% or 9% too high, B is at 26% or 14% too low. C is at 15% or 5% too high.

Suppose I want to withdraw $50,000 from this account. I would like to do it so as to bring the funds as close to the target percentages as possible. In the Withdrawal Amount column, I found the correct allocation by trial and error.

Is there a formula that will calculate the best way to divide up a withdrawal from 3 index funds to achieve the best balance? Or do I need to write a macro that will do the trial and error for me?

Thanks

Rebalance.xlsx
BCDEFGHIJKLM
3$224,245.86Current Total (TotOld)
4$50,000.00Withdrawal Amount (WDAmt)
5$174,245.86Adjusted Total (TotAdj)Table Name: TblRebalMan
6FundTarget %Old BalancesOld %Old % - Tgt %Target BalancesTarget Rebalance △Withdrawal AmountRebalanced BalanceTarget - ActualRebalanced %Rebalanced% - Target%
7A50%$131,931.4658.83%+8.83%$87,122.93-$44,808.53$39,524.36$92,407.10-$5,284.1753.03%+3.03259%
8B40%$59,130.0026.37%-13.63%$69,698.34+$10,568.34$0.00$59,130.00+$10,568.3433.93%-6.06519%
9C10%$33,184.4014.80%+4.80%$17,424.59-$15,759.81$10,475.64$22,708.76-$5,284.1713.03%+3.03260%
10Total100%$224,245.86100.00%0.00%$174,245.86-$50,000.00$50,000.00$174,245.86$0.00100.00%+0.00000%
Rebalance Manual
Cell Formulas
RangeFormula
D3D3=TblRebalMan[[#Totals],[Old Balances]]
E3E3="Current Total (" & GetRangeName(TotOld) & ")"
E4E4="Withdrawal Amount (" & GetRangeName(WDAmt) & ")"
D5D5=TblRebalMan[[#Totals],[Old Balances]]-WDAmt
E5E5="Adjusted Total (" & GetRangeName(TotAdj) & ")"
I5I5=+GetTableName(TblRebalMan[[#Headers],[Fund]])
E7:E9E7=[@[Old Balances]]/TblRebalMan[[#Totals],[Old Balances]]
F7:F9F7=[@[Old %]]-[@[Target %]]
G7:G9G7=[@[Target %]]*TotAdj
H7:H9H7=[@[Target Balances]]-[@[Old Balances]]
J7:J9J7=[@[Old Balances]]-[@[Withdrawal Amount]]
K7:K9K7=[@[Target Balances]]-[@[Rebalanced Balance]]
L7:L9L7=[@[Rebalanced Balance]]/TblRebalMan[[#Totals],[Rebalanced Balance]]
M7:M9M7=[@[Rebalanced %]]-[@[Target %]]
I9I9=WDAmt-TAKE([Withdrawal Amount],1)
C10C10=SUBTOTAL(109,[Target %])
D10D10=SUBTOTAL(109,[Old Balances])
E10E10=SUBTOTAL(109,[Old %])
F10F10=SUBTOTAL(109,[Old % - Tgt %])
G10G10=SUBTOTAL(109,[Target Balances])
H10H10=SUBTOTAL(109,[Target Rebalance △])
I10I10=SUBTOTAL(109,[Withdrawal Amount])
J10J10=SUBTOTAL(109,[Rebalanced Balance])
K10K10=SUBTOTAL(109,[Target - Actual])
L10L10=SUBTOTAL(109,[Rebalanced %])
M10M10=SUBTOTAL(109,[Rebalanced% - Target%])
Named Ranges
NameRefers ToCells
'Rebalance Manual'!TotAdj='Rebalance Manual'!$D$5E5, G7:G9
'Rebalance Manual'!TotOld='Rebalance Manual'!$D$3E3
'Rebalance Manual'!WDAmt='Rebalance Manual'!$D$4I9, E4, D5
 
Now for some larger withdrawals.

1735431483027.png


This is the maximum withdrawal that only affects two of these funds. And notice that all three funds are now at their target percentages.

1735431683504.png


One penny more, and it starts affecting the third fund.

1735431741644.png


And some much larger withdrawals...

1735431947856.png


1735431983837.png


A total withdrawal.

1735432064812.png


With one penny more, it tries to withdraw more than is available.

1735432149316.png
 
Upvote 0

Excel Facts

Copy a format multiple times
Select a formatted range. Double-click the Format Painter (left side of Home tab). You can paste formatting multiple times. Esc to stop
After:
VBA Code:
With ActiveSheet
insert:
VBA Code:
  .Range("WDAmt").Value = Abs(.Range("WDAmt").Value)
  If .Range("WDAmt").Value > .Range("TotOld").Value Then
    MsgBox "Insufficient Funds!", vbExclamation: Exit Sub
  End If
 
Upvote 0
After:
VBA Code:
With ActiveSheet
insert:
VBA Code:
  .Range("WDAmt").Value = Abs(.Range("WDAmt").Value)
  If .Range("WDAmt").Value > .Range("TotOld").Value Then
    MsgBox "Insufficient Funds!", vbExclamation: Exit Sub
  End If

That works perfectly. I implemented it slightly differently. Here's the entire macro.

VBA Code:
Sub Withdrawals()
Application.ScreenUpdating = False
Debug.Print Time()

' Define table columns
Const cTgtPC As String = "C"           'Column with Target fund percentages
Const cOldBal As String = "D"          'Column with Old fund balances
Const cOldPC As String = "E"           'Column with Old fund percentages
Const cTgtRebal As String = "H"        'Column with Target rebalance delta
Const cWDAmt As String = "I"           'Column with Withdrawal amounts

'Define named ranges
Const nTotalOld As String = "TotOld"   'Name of Old fund total cell
Const nWDAmt As String = "WDAmt"       'Name of withdrawal amount cell
Const nTotAdj As String = "TotAdj"     'Name of adjusted total cell

Dim row As Long      'Row number
Dim i As Long        'Number of funds over the target %
Dim Val As Double    'The withdrawal value
Dim TgtPct As Double 'Sum of target %s

i = 0       'Zero the count
Val = 0     'Zero withdrawal
TgtPct = 0  'Zero the target %

With ActiveSheet
  'Check for out of range withdrawal amounts
  'Macropod's code
  '.Range(nWDAmt).Value = Abs(.Range(nWDAmt).Value)
  'If .Range(nWDAmt).Value > .Range(nTotalOld).Value Then
  '   MsgBox "Insufficient Funds!", vbExclamation: Exit Sub
  'End If
  'My modified code
Debug.Print "WDAmt = " & .Range(nWDAmt).Value
Debug.Print "WDAmt = " & .Range(nWDAmt).Value
  Select Case .Range(nWDAmt).Value
    Case Is > .Range(nTotalOld).Value
      MsgBox "Withdrawal amount too large", vbExclamation: Exit Sub
    Case Is < 0
      MsgBox "Withdrawal < 0", vbExclamation: Exit Sub
  End Select
  'Collect data from the index fund rows in use
  For row = 7 To 9
    'Check each index fund for an excess balance
    If .Range(cTgtRebal & row).Value < 0 Then
      'Sum the $ of each index fund with excess balance
      Val = Val + .Range(cOldBal & row).Value
      'Sum the % of each index fund with excess balance
      TgtPct = TgtPct + .Range(cTgtPC & row).Value
      'Update counter for index funds with excess balance
      i = i + 1
    End If
  Next row
  'Calculate the required target % variance to be applied to each of the original % figures
  'Basically, Val minus WDAmt, divided by TotAdj, then subtract TgtPct. This gives the
  'required overall % adjustment. Divide the result by the count of adjustment items to get
  'the required individual index fund % adjustment.
  TgtPct = ((Val - .Range(nWDAmt).Value) / .Range(nTotAdj).Value - TgtPct) / i
  'Update the index fund rows in use
  For row = 7 To 9
    'If the actual % is greater than the target %, calculate the withdrawal value
    If .Range(cOldPC & row).Value > .Range(cTgtPC & row).Value Then
      'Sum the required target % variance and the original %,
      'then multiply by TotAdj and subtract the old index fund $
      Val = (.Range(cTgtPC & row).Value + TgtPct) * .Range(nTotAdj).Value - .Range(cOldBal & row).Value
    Else
      Val = 0
    End If
    'If the calculated withdrawal $ exceeds the total withdrawal $,
    'reduce the calculated withdrawal $ accordingly
    If Val < -.Range(nWDAmt).Value Then Val = -.Range(nWDAmt).Value
    'Avoid potential implied credits arising out of small WDAmt
    If Val > 0 Then Val = 0
    'Output the result in column I rounded to dollars and cents
    .Range(cWDAmt & row).Value = Format(Val, "$#,##0.00")
  Next row
  'Calculate the allocated $
  Val = 0
  For row = 7 To 9
    Val = Val + .Range(cWDAmt & row).Value
  Next row
  Val = -(Val + .Range(nWDAmt).Value)
  'If Val <> 0 then a remainder of withdrawal needs to be allocated
  If Val <> 0 Then
    For row = 7 To 9
      'Check each index fund omitted from first round
      If .Range(cWDAmt & row).Value = 0 Then TgtPct = TgtPct + .Range(cTgtPC & row).Value
    Next row
    For row = 7 To 9
      'Apportion Val between index funds omitted from first round
      If .Range(cWDAmt & row).Value = 0 Then
         .Range(cWDAmt & row).Value = Format(Val * .Range(cTgtPC & row).Value / TgtPct, "$#,##0.00")
      End If
    Next row
  End If
End With

Application.ScreenUpdating = True
End Sub
 
Upvote 0
Now the only thing that is needed is for it to use table notation, rather than row/column notation, so the table doesn't need to be in a particular range.

I'd suggest requiring a set of names that would be assigned specific cells and table column headers.
 
Upvote 0

Forum statistics

Threads
1,225,136
Messages
6,183,067
Members
453,147
Latest member
Lacey D

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top