Skip to content

Instantly share code, notes, and snippets.

@3gx
Last active February 17, 2021 16:56
Show Gist options
  • Select an option

  • Save 3gx/27181adc9086d82c7c9dd3cf55d0462d to your computer and use it in GitHub Desktop.

Select an option

Save 3gx/27181adc9086d82c7c9dd3cf55d0462d to your computer and use it in GitHub Desktop.
portoflio model
import random
from math import log, exp
def get_f(fmax):
f = 1+random.randrange(-fmax*100//10,2*fmax*100)/100.0/100.0
f = 1+random.gauss(fmax,fmax/2)/100
f = 1 + fmax/100
assert f > 0
return f
def usmodel(fmax,n,tax):
xbefore=1
xafter=1
for i in range(0,n):
f = get_f(fmax)
xbefore *= f # just compounded growth for n-years
xafter *= f # tax on profit after this compounded growth
xafter = 1 + (xafter-1)*(1-tax) # tax amount of final profits
tax=1-(xafter-1)/(xbefore-1) # effective tax
cagr = exp(log(xbefore)/n)
return xbefore, xafter, 1-xafter/xbefore, tax, cagr
def nlmodel(fmax, n,tax):
xbefore=1
xafter=1
for i in range(0,n):
f = get_f(fmax)
xbefore *= f # just compounded growth for n-years
xafter*= f*(1-tax/2) - tax/2 # wealth tax applied on yearly basis at the end of the year
tax=1-(xafter-1)/(xbefore-1) # effective tax
cagr = exp(log(xbefore)/n)
return xbefore, xafter, 1-xafter/xbefore, tax, cagr
def usmodel_rebalance(fmax,n,tax,nr,ar):
assert n%nr == 0 # sanity check, keep things simple
xbefore=1
xafter=1
for i in range(0,n,nr):
f = get_f(fmax)
xbefore *= f**nr # grow for nr years
xafter *= (f**nr-1)*ar*(1-tax) + (f**nr-1)*(1-ar) + 1 # tax ar amount of profits that need to be rebalanced
xafter /= (f**nr-1)*ar*(1-tax) + (f**nr-1)*(1-ar) + 1 # undo final rebalancing
xafter *= f**nr # just grow for the final year
xafter = 1 + (xafter-1)*(1-tax) # tax amount of final profits
tax=1-(xafter-1)/(xbefore-1) # effective tax
cagr = exp(log(xbefore)/n)
return xbefore, xafter, 1-xafter/xbefore, tax, cagr
flist = [3,5,7,10,15,20] # CAGR rates
nyears = [2,4,6,10,20,30,40,50] # years to invest
tax=0.3 # US federal + state capital gain taxes, ca is 20+13.3 = 33.3, other states can be lower
print(f"\n\nUS Model, tax={tax}")
for f in flist:
print(f"\nf={f}")
for n in nyears:
print(f"{n}yr: {usmodel(f,n,tax)}")
nr=1 # rebalance every year
ar=0.3 # profits imbalance that needs to be sold and reinvested
print(f"\n\nUS Model with rebalance, tax={tax} nr={nr} ar={ar}")
for f in flist:
print(f"\nf={f}")
for n in nyears:
print(f"{n}yr: {usmodel_rebalance(f,n,tax,nr,ar)}")
tax=0.04*0.3 # NL wealth tax, 30% assuming 4% growth of wealth
print(f"\n\nNL Model, tax={tax}")
for f in flist:
print(f"\nf={f}")
for n in nyears:
print(f"{n}yr: {nlmodel(f,n,tax)}")
@3gx
Copy link
Author

3gx commented Feb 17, 2021

$ python capital_gain_taxes.py


US Model, tax=0.3

f=1.03
10yr: (1.3439163793441222, 1.2407414655408855, 0.07677182553098261, 0.30000000000000016)
20yr: (1.8061112346694148, 1.5642778642685902, 0.13389727374409977, 0.30000000000000027)
30yr: (2.427262471189662, 1.9990837298327635, 0.17640397214522807, 0.30000000000000004)
40yr: (3.2620377919990777, 2.5834264543993544, 0.20803294776785808, 0.30000000000000004)
50yr: (4.383906018707096, 3.368734213094967, 0.23156787606307405, 0.30000000000000004)

f=1.05
10yr: (1.628894626777442, 1.4402262387442093, 0.1158260239377723, 0.30000000000000016)
20yr: (2.653297705144422, 2.1573083936010953, 0.18693315513809994, 0.30000000000000016)
30yr: (4.321942375150668, 3.325359662605467, 0.23058676540324274, 0.30000000000000016)
40yr: (7.039988712124658, 5.2279920984872605, 0.25738629530991675, 0.30000000000000004)
50yr: (11.4673997857537, 8.32717985002759, 0.27383888190828587, 0.29999999999999993)

f=1.07
10yr: (1.9671513572895665, 1.6770059501026964, 0.14749521235958485, 0.30000000000000016)
20yr: (3.8696844624861835, 3.0087791237403283, 0.2224742991558395, 0.30000000000000004)
30yr: (7.612255042662042, 5.628578529863429, 0.26058986485362323, 0.30000000000000016)
40yr: (14.974457839206984, 10.782120487444889, 0.2799658856954058, 0.30000000000000004)
50yr: (29.457025063071406, 20.919917544149982, 0.2898156721747136, 0.30000000000000004)

f=1.1
10yr: (2.5937424601000023, 2.1156197220700017, 0.1843370131711406, 0.29999999999999993)
20yr: (6.727499949325611, 5.009249964527927, 0.25540691159275697, 0.30000000000000004)
30yr: (17.44940226888645, 12.514581588220514, 0.2828074340096496, 0.30000000000000004)
40yr: (45.2592555681761, 31.981478897723267, 0.2933715215543461, 0.30000000000000004)
50yr: (117.39085287969579, 82.47359701578705, 0.2974444346161498, 0.30000000000000004)

f=1.15
10yr: (4.045557735707907, 3.1318904149955347, 0.22584458816344022, 0.30000000000000004)
20yr: (16.36653739294609, 11.756576175062262, 0.281669916317834, 0.30000000000000004)
30yr: (66.21177195678577, 46.648240369750035, 0.29546908365183466, 0.30000000000000004)
40yr: (267.86354623470254, 187.80448236429177, 0.29888002677401604, 0.30000000000000004)
50yr: (1083.6574415839534, 758.8602091087673, 0.2997231597472708, 0.30000000000000004)

f=1.2
10yr: (6.191736422399997, 4.634215495679998, 0.25154832513304637, 0.30000000000000004)
20yr: (38.33759992447472, 27.136319947132304, 0.2921747840086234, 0.30000000000000004)
30yr: (237.37631379976955, 166.46341965983868, 0.29873618393007384, 0.30000000000000004)
40yr: (1469.7715679690843, 1029.140097578359, 0.29979588664896106, 0.30000000000000004)
50yr: (9100.438150002134, 6370.6067050014935, 0.2999670345542649, 0.30000000000000004)


US Model with rebalance, tax=0.3 nr=1  ar=0.3

f=1.03
10yr: (1.3439163793441222, 1.218778571657, 0.09311428122350418, 0.3638611453335563)
20yr: (1.806111234669415, 1.5027731895645946, 0.16795092089681973, 0.37629799965412825)
30yr: (2.4272624711896627, 1.8745505937587963, 0.2277099753286954, 0.38725314270343403)
40yr: (3.2620377919990777, 2.3612444589022257, 0.276144358384278, 0.39822205282466794)
50yr: (4.383906018707096, 2.998375483262488, 0.31604932439980304, 0.4094471086918613)

f=1.05
10yr: (1.628894626777442, 1.3969925381398534, 0.1423677657383996, 0.3687455398146626)
20yr: (2.6532977051444226, 2.011764616791753, 0.24178707391515641, 0.38803240720438115)
30yr: (4.321942375150668, 2.9710647533380574, 0.31256261758129467, 0.4066529365222179)
40yr: (7.03998871212466, 4.467971955102554, 0.3653438751389524, 0.42583138472743254)
50yr: (11.467399785753704, 6.8037697782547015, 0.40668591787414354, 0.4455385389833182)

f=1.07
10yr: (1.9671513572895665, 1.6057326110253953, 0.18372696382760845, 0.37369408990651076)
20yr: (3.8696844624861844, 2.7212846193530575, 0.29676834229406546, 0.40018331567304)
30yr: (7.6122550426620466, 4.789907932460805, 0.37076360347672377, 0.4268357908144125)
40yr: (14.974457839206995, 8.625858546675445, 0.42396187966881027, 0.45430022155992367)
50yr: (29.457025063071416, 15.739051664753417, 0.46569446062343334, 0.48205929354575316)

f=1.1
10yr: (2.5937424601000023, 1.9862170661461729, 0.23422733879693136, 0.38119420744786403)
20yr: (6.72749994932561, 4.328663430690135, 0.35657176316678285, 0.41882785506055364)
30yr: (17.449402268886445, 9.925171849834108, 0.43120276002053026, 0.4574166462743874)
40yr: (45.25925556817607, 23.296195818464913, 0.4852722271719031, 0.49623653782155697)
50yr: (117.39085287969573, 55.24187847984216, 0.5294192253935233, 0.5339678579732738)

f=1.15
10yr: (4.0455577357079076, 2.846366082801311, 0.2964218363075116, 0.39375108173014406)
20yr: (16.36653739294609, 9.454091340017237, 0.42235238199547864, 0.4498375838464407)
30yr: (66.21177195678578, 33.2086178249717, 0.49844843532286287, 0.5060919699235356)
40yr: (267.8635462347026, 118.60525684354877, 0.5572176262475574, 0.5593056507608699)
50yr: (1083.6574415839539, 425.6029972652788, 0.607253195582558, 0.6078140869340218)

f=1.2
10yr: (6.191736422399999, 4.083002035479589, 0.34057237631944237, 0.4061713105892999)
20yr: (38.33759992447473, 20.43776833490868, 0.46690016132540413, 0.47940498654903485)
30yr: (237.37631379976963, 107.49785760280186, 0.5471416002631254, 0.5494563059604425)
40yr: (1469.7715679690846, 570.9382397254199, 0.6115462755111418, 0.6119626413292498)
50yr: (9100.438150002134, 3037.9353400967093, 0.6661770246638072, 0.6662502354504165)


NL Model, tax=0.012

f=1.03
10yr: (1.3439163793441222, 1.1931905479803084, 0.11215417393556382, 0.43826302094497727)
20yr: (1.8061112346694148, 1.4237036837895485, 0.2117297891399591, 0.4743855865458707)
30yr: (2.427262471189662, 1.698749778622435, 0.3001375834769796, 0.5104265734388658)
40yr: (3.2620377919990777, 2.026932179235931, 0.37863007467066645, 0.5460145790365515)
50yr: (4.383906018707096, 2.4185163176614406, 0.448319305354381, 0.5808050490115504)

f=1.05
10yr: (1.628894626777442, 1.4478319871982184, 0.11115675415875903, 0.2879061640373968)
20yr: (2.653297705144422, 2.096217463154342, 0.20995768432240713, 0.3369509558119279)
30yr: (4.321942375150668, 3.0349706952783593, 0.29777622378119817, 0.3874154137950504)
40yr: (7.039988712124658, 4.394127652833225, 0.37583313943878704, 0.43805728543501055)
50yr: (11.4673997857537, 6.3619585716041716, 0.44521350171223417, 0.48774684435939064)

f=1.07
10yr: (1.9671513572895665, 1.7503797982359253, 0.11019566859985763, 0.224134058666)
20yr: (3.8696844624861835, 3.063829438072438, 0.20824825182154572, 0.28081659671934245)
30yr: (7.612255042662042, 5.362865153642522, 0.2954958650771766, 0.34018498598534597)
40yr: (14.974457839206984, 9.387050825599273, 0.3731291692563614, 0.399829966779218)
50yr: (29.457025063071406, 16.430904130142828, 0.44220761957590493, 0.4577471082819734)

f=1.1
10yr: (2.5937424601000023, 2.3114967473766597, 0.10881794051074012, 0.1770961869872204)
20yr: (6.727499949325611, 5.343017213132878, 0.2057945368444809, 0.24172549077992567)
30yr: (17.44940226888645, 12.350366909334152, 0.2922183396874428, 0.30998301799676753)
40yr: (45.2592555681761, 28.547832939834226, 0.3692376822939275, 0.3775802917109603)
50yr: (117.39085287969579, 65.98822298507908, 0.4378759386584833, 0.4416380550776411)

f=1.15
10yr: (4.045557735707907, 3.61398707749883, 0.1066776663202309, 0.14170496692579126)
20yr: (16.36653739294609, 13.060902596328534, 0.20197520814893144, 0.21511904159586315)
30yr: (66.21177195678577, 47.20193320360224, 0.2871066306092914, 0.2915093116282882)
40yr: (267.86354623470254, 170.5871766307814, 0.3631564315910586, 0.36451726350952407)
50yr: (1083.6574415839534, 616.4998519306545, 0.43109341727997275, 0.4314915980901922)

f=1.2
10yr: (6.191736422399997, 5.5433892647876695, 0.10471168560515376, 0.1248805996419623)
20yr: (38.33759992447472, 30.72916454096318, 0.198458834108035, 0.20377408828906085)
30yr: (237.37631379976955, 170.34372083226918, 0.2823895606705029, 0.28358422165886965)
40yr: (1469.7715679690843, 944.2815533855887, 0.3575317593805495, 0.35777518168472366)
50yr: (9100.438150002134, 5234.5202259746975, 0.4248056918035896, 0.4248523766301472)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment