Compound interest has been described as the eight wonder of the world. I have passion for finance and investing, and I am digging deep into the Pandas library these days. That presented a good opportunity to use Pandas-enabled visualizataion to demonstrate the power of compounding! A common investment advice is to start early, and to stay invested over a long period of time. To demonstrate the power of money compounding, I create my own dataset (code below) outlining this scenario -

  • Jack and Jill are two investors
  • Jack starts investing early, and starts contributing $2000 every year from age 25, and stops contributing age 34
  • Jill starts investing later at age 35, and continues contributing $2000 every year till age 65
  • Jack stays invested in the market from age 25 all the way to 65, and Jill stays invested all the way to 65 too
  • Both of them earn 8% on their returns each year

Here’s a chart of how their returns stack up -

agejack investsjack_returnsjill_investsjill_returnsjack_total_investmentjill_total_investment
25200021600020000
2620004492.80040000
2720007012.220060000
2820009733.20080000
29200012671.8600100000
30200015845.6100120000
31200019273.2600140000
32200022975.1200160000
33200026973.1200180000
34200031290.9700200000
35035954.2520002160200002000
36038830.5920004492.8200004000
37041937.0420007012.22200006000
3804529220009733.2200008000
39048915.36200012671.862000010000
40052828.59200015845.612000012000
41057054.88200019273.262000014000
42061619.27200022975.122000016000
43066548.81200026973.122000018000
44071872.72200031290.972000020000
45077622.54200035954.252000022000
46083832.34200040990.592000024000
47090538.93200046429.842000026000
48097782.04200052304.232000028000
490105604.6200058648.572000030000
500114052.97200065500.452000032000
510123177.21200072900.492000034000
520133031.38200080892.532000036000
530143673.9200089523.932000038000
540155167.81200098845.842000040000
550167581.232000108913.512000042000
560180987.732000119786.592000044000
570195466.752000131529.522000046000
580211104.092000144211.882000048000
590227992.422000157908.832000050000
600246231.812000172701.542000052000
610265930.352000188677.662000054000
620287204.782000205931.872000056000
630310181.162000224566.422000058000
640334995.662000244691.742000060000
650361795.312000266427.072000062000

Plotting these using Plotly we can see the power of compounding. The following figure shows how the total returns for Jack and Jill grows.

Returns

This following barplot show how their final returns stack up and their total contributions.

Return Values

So here’s the power of compounding - Jack ends up with $361,795 with a net contribution of $20,000, while Jill ends up with a total of $266,427 with a net contribution of 62K! So just because Jack started contributing early he was able to grow his pile much more than Jill, who ended up contributing about $40K more than Jack!

Note that the scenario I present here does assume -

  • an idealized and consistent return of 8%,
  • investment into a broad stock index like a total stock market index

However, there are studies showing that invested in a broad market index yields greater than 6% if you stay invested over a long period.

Finally, this is the complete Python program I used to both generate the dataset, and to plot the results

import pandas as pd
import plotly.graph_objects as go
import plotly.express as px

if __name__ == "__main__":
    def returns(age_start: int, age_stop: int, s_age: int, early_investor: bool) -> list:
        initial_investment_age_stop = s_age
        annual_contribution = 2000
        annual_return_rate = 0.08

        # Initialize variables
        total_amount = 0
        returns_list = []

        # Loop through each year, simulating the investment growth
        for age in range(age_start, age_stop + 1):
            if early_investor:
                if age <= initial_investment_age_stop:
                    # Add principal for ages 19 to 27
                    total_amount += annual_contribution
            else:
                if age >= initial_investment_age_stop:
                    # Add principal for ages 28 to 64
                    total_amount += annual_contribution
            # Calculate the growth for the year
            total_amount *= (1 + annual_return_rate)
            # Add the total amount for the year to the list
            returns_list.append(total_amount)

        # Adjust the list to show the total amount at the end of each year, rounded to 2 decimal places
        returns_list = [round(amount, 2) for amount in returns_list]

        return returns_list

    # Create a dataframe according to the following:
    # 1. Create a datafrom with an age column from age 19 to 65
    # 2. Create column #2 called 'jack_invests' with value 2000 from age 19 to 27, and then 0 from age 28 to 64
    # 3. Create column #4 called 'jack_returns' with initial 2000 compounded at 6% from age 19 to 64, and also adding
    #   2000 from age 19 to 27
    # 4. Create column #3 called 'jill_invests' with value 0 from age 19 to 27, and then 2000 from age 28 to 64
    # 5. Create column #5 called 'jill_returns' with initial 2000 compounded at 8% from age 19 to 64, and also adding
    #   2000 from age 28 to 64
    start_age = 25
    end_age = 65
    s_age = 35
    df = pd.DataFrame({'age': range(start_age, end_age + 1),
                       'jack_invests': [2000 if age < s_age else 0 for age in range(start_age, end_age + 1)],
                       'jack_returns': returns(start_age, end_age, s_age, True),
                       'jill_invests': [0 if age < s_age else 2000 for age in range(start_age, end_age + 1)],
                       'jill_returns': returns(start_age, end_age, s_age, False)
                       })

    # Plot the returns of Jack and Jill using plotly as a bar plot
    fig = px.bar(df, x='age', y=['jack_returns', 'jill_returns'], title='Returns of Jack and Jill', barmode='group')
    fig.update_layout(xaxis_title='Age', yaxis_title='Return')
    fig.show()

    # Plot total investment of Jack and Jill using plotly. Also plot the total returns on investment as a percentage
    # of the total investment at age 65
    df['jack_total_investment'] = df['jack_invests'].cumsum()
    df['jill_total_investment'] = df['jill_invests'].cumsum()

    jack_total_investment = df['jack_total_investment'].iloc[-1]
    jill_total_investment = df['jill_total_investment'].iloc[-1]
    jack_final_return = df['jack_returns'].iloc[-1]
    jill_final_return = df['jill_returns'].iloc[-1]

    jack_total_return = (jack_final_return - jack_total_investment) / jack_total_investment * 100
    jill_total_return = (jill_final_return - jill_total_investment) / jill_total_investment * 100

    fig = go.Figure()
    fig.add_trace(go.Bar(x=['Jack Total Contribution'], y=[jack_total_investment], name='Jack Total Contributions', marker_color='rgb(55, 83, 109)'))
    fig.add_trace(go.Bar(x=['Jack Total Return'], y=[jack_final_return], name='Jack Total Return', marker_color='rgb(26, 118, 255)'))
    fig.add_trace(go.Bar(x=['Jill Total Contribution'], y=[jill_total_investment], name='Jill Total Contributions', marker_color='rgb(255, 153, 51)'))
    fig.add_trace(go.Bar(x=['Jill Total Return'], y=[jill_final_return], name='Jill Total Return', marker_color='rgb(255, 99, 71)'))
    fig.show()