Creating a Mutual Fund Plan with Python//

Creating a Mutual Fund Plan with Python

Mutual funds are investment plans that pool money from multiple investors to purchase a diversified portfolio of stocks, bonds, and other securities, managed by professional fund managers. A mutual fund plan is created by selecting the stocks where an investor can benefit in the long term.

A mutual fund plan is created by selecting the stocks where an investor can benefit in the long term. Here’s the process we can follow to create a mutual fund plan:

Step 1: Gather historical stock data, such as closing prices and growth trends over time.

Step 2: Calculate key metrics like Return on Investment (ROI) and volatility (risk) to understand how each stock has performed historically.

Step 3: Choose stocks that have a high ROI and low volatility to ensure a balance between risk and reward.

Step 4: Calculate the future value of monthly investments based on the expected ROI of the selected stocks.

1
!pip install yfinance
Requirement already satisfied: yfinance in /usr/local/lib/python3.10/dist-packages (0.2.50)
Requirement already satisfied: pandas>=1.3.0 in /usr/local/lib/python3.10/dist-packages (from yfinance) (2.2.2)
Requirement already satisfied: numpy>=1.16.5 in /usr/local/lib/python3.10/dist-packages (from yfinance) (1.26.4)
Requirement already satisfied: requests>=2.31 in /usr/local/lib/python3.10/dist-packages (from yfinance) (2.32.3)
Requirement already satisfied: multitasking>=0.0.7 in /usr/local/lib/python3.10/dist-packages (from yfinance) (0.0.11)
Requirement already satisfied: lxml>=4.9.1 in /usr/local/lib/python3.10/dist-packages (from yfinance) (5.3.0)
Requirement already satisfied: platformdirs>=2.0.0 in /usr/local/lib/python3.10/dist-packages (from yfinance) (4.3.6)
Requirement already satisfied: pytz>=2022.5 in /usr/local/lib/python3.10/dist-packages (from yfinance) (2024.2)
Requirement already satisfied: frozendict>=2.3.4 in /usr/local/lib/python3.10/dist-packages (from yfinance) (2.4.6)
Requirement already satisfied: peewee>=3.16.2 in /usr/local/lib/python3.10/dist-packages (from yfinance) (3.17.8)
Requirement already satisfied: beautifulsoup4>=4.11.1 in /usr/local/lib/python3.10/dist-packages (from yfinance) (4.12.3)
Requirement already satisfied: html5lib>=1.1 in /usr/local/lib/python3.10/dist-packages (from yfinance) (1.1)
Requirement already satisfied: soupsieve>1.2 in /usr/local/lib/python3.10/dist-packages (from beautifulsoup4>=4.11.1->yfinance) (2.6)
Requirement already satisfied: six>=1.9 in /usr/local/lib/python3.10/dist-packages (from html5lib>=1.1->yfinance) (1.17.0)
Requirement already satisfied: webencodings in /usr/local/lib/python3.10/dist-packages (from html5lib>=1.1->yfinance) (0.5.1)
Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.10/dist-packages (from pandas>=1.3.0->yfinance) (2.8.2)
Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.10/dist-packages (from pandas>=1.3.0->yfinance) (2024.2)
Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests>=2.31->yfinance) (3.4.0)
Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests>=2.31->yfinance) (3.10)
Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests>=2.31->yfinance) (2.2.3)
Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests>=2.31->yfinance) (2024.8.30)
import yfinance as yf
import pandas as pd
from datetime import date, timedelta, datetime
# List of example tickers across various sectors (ticker are symbols, a unique combination of letters and numbers that represent a particular stock or security listed on an exchange.)
tickers = [ "JPM", "BAC", "WFC", "C", "GS", "AAPL", "MSFT", "GOOGL", "AMZN", "FB", "PG", "KO", "PEP", "CL", "MNST","TSLA", "GM", "F", "HMC", "TM",
 "XOM", "CVX", "JNJ", "PFE", "MRK",
    "NKE", "DIS", "VZ", "T", "CSCO",
    "ORCL", "IBM", "INTC", "AMD", "NVDA",
    "ADBE", "NFLX", "COST", "WMT", "HD",
    "MCD", "SBUX", "UPS", "FDX", "CAT",
    "MMM", "BA", "GE", "HON", "DOW"
]
end_date = datetime.today()
print(end_date)

2024-12-14 20:55:53.790207

start_date = end_date - timedelta(days = 365) #just selected for the past 1 year, but this can be easily modified with prefrence i.e (days = year*365)
print(start_date)
close_df = pd.DataFrame()
for ticker in tickers:
    data = yf.download(ticker, start=start_date, end=end_date)
 
    data.reset_index(inplace=True)
 
    close_df['Date'] = data['Date']
    close_df[ticker] = data['Close']
 
# Remove any duplicate 'Date' columns if present
close_df = close_df.loc[:, ~close_df.columns.duplicated()]
print(close_df)
data['Date'] = pd.to_datetime(data['Date'])
print(data)
import plotly.graph_objs as go
import plotly.express as px
 
 
fig = go.Figure()
 
for company in close_df.columns[1:]:  # skip 'Date' column
    fig.add_trace(go.Scatter(x=close_df['Date'], y=close_df[company],
                             mode='lines',
                             name=company,
                             opacity=0.5))
 
fig.update_layout(
    title='Stock Price Trends of Top 50 S&P 500 Companies',
    xaxis_title='Date',
    yaxis_title='Closing Price (USD)',
    xaxis=dict(tickangle=45),
    legend=dict(
        x=1.05,
        y=1,
        traceorder="normal",
        font=dict(size=10),
        orientation="v"
    ),
    margin=dict(l=0, r=0, t=30, b=0),
    hovermode='x',
    template='plotly_white'
)
 
fig.show()
import plotly.graph_objs as go
import plotly.express as px
from plotly.subplots import make_subplots
 
# Create a more interactive and visually appealing figure
fig = make_subplots(specs=[[{"secondary_y": True}]])
 
# Define color palette for lines
colors = px.colors.qualitative.Plotly  # Get a set of unique colors
 
# Add a line trace for each company with enhanced hover info and colors
for i, company in enumerate(close_df.columns[1:]):  # skip 'Date' column
    fig.add_trace(go.Scatter(
        x=close_df['Date'],
        y=close_df[company],
        mode='lines',
        name=company,
        line=dict(color=colors[i % len(colors)], width=1.5),  # Use colors in a loop
        opacity=0.7,
        hovertemplate=f"<b>{company}</b><br>Date: {{x}}<br>Closing Price: {{y}}<extra></extra>"
    ))
 
# Update layout with enhanced styling
fig.update_layout(
    title={
        'text': 'Stock Price Trends of Top 50 S&P 500 Companies',
        'y':0.9,
        'x':0.5,
        'xanchor': 'center',
        'yanchor': 'top',
        'font': dict(size=20, color="RebeccaPurple")
    },
    xaxis=dict(
        title='Date',
        tickangle=45,
        tickformat='%b %d, %Y',
        rangeslider=dict(visible=True# Add a range slider for better navigation
    ),
    yaxis_title='Closing Price (USD)',
    legend=dict(
        x=1.05,
        y=1,
        traceorder="normal",
        font=dict(size=10),
        orientation="v"
    ),
    margin=dict(l=20, r=20, t=50, b=50),
    hovermode='x unified'# Unified hover mode for a cleaner look
    template='plotly_dark'# Dark theme for a more professional look
)
 
# Add animation options
fig.update_layout(
    updatemenus=[dict(type="buttons",
                      direction="left",
                      buttons=[dict(label="Play",
                                    method="animate",
                                    args=[None, dict(frame=dict(duration=100, redraw=True), fromcurrent=True)])],
                      pad={"r": 10, "t": 10},
                      showactive=True,
                      x=0.1,
                      xanchor="right",
                      y=1.15,
                      yanchor="top"
                      )]
)
 
# Set up frames for animation
frames = [go.Frame(
    data=[go.Scatter(
        x=close_df['Date'][:k+1],
        y=close_df[company][:k+1]
    ) for company in close_df.columns[1:]],
    name=f"frame{k}"
) for k in range(0, len(close_df['Date']), 5)]  # Adjust step for smoother/faster animation
 
fig.frames = frames
 
fig.show()
all_companies = close_df.columns[1:]
 
# Calculate the standard deviation (volatility) for each company's closing price
volatility_all_companies = close_df[all_companies].std()
 
# Sort and display the top 10 companies with the highest volatility
top_10_volatile_companies = volatility_all_companies.sort_values(ascending=False).head(10)
 
print("Top 10 Companies with Highest Volatility (Investment Risk):")
print(top_10_volatile_companies)
growth_all_companies = close_df[all_companies].pct_change() * 100
 
average_growth_all_companies = growth_all_companies.mean()
 
average_growth_all_companies.sort_values(ascending=False).head(10)
initial_prices_all = close_df[all_companies].iloc[0]
final_prices_all = close_df[all_companies].iloc[-1]
 
roi_all_companies = ((final_prices_all - initial_prices_all) / initial_prices_all) * 100
 
roi_all_companies.sort_values(ascending=False).head(10)

Creating a Mutual Fund Plan Based on High ROI and Low Risk

  1. Define ROI and Volatility Thresholds: We will set thresholds for ROI and volatility to select companies that provide good returns with lower risks.
  2. Rank Companies by ROI and Volatility: Rank all companies based on their ROI and volatility scores.
  3. Assign Investment Ratios: Allocate more investment to companies with higher ROI and lower volatility.
roi_threshold = roi_all_companies.median()
volatility_threshold = volatility_all_companies.median()
 
selected_companies = roi_all_companies[(roi_all_companies > roi_threshold) & (volatility_all_companies < volatility_threshold)]
 
selected_companies.sort_values(ascending=False)
roi_threshold = roi_all_companies.median()
volatility_threshold = volatility_all_companies.median()
 
selected_companies = roi_all_companies[(roi_all_companies > roi_threshold) & (volatility_all_companies < volatility_threshold)]
 
selected_companies = selected_companies.sort_values(ascending=False)
 
formatted_output = [f"{company} (ROI: {roi:.2f}%)" for company, roi in selected_companies.items()]
 
print("The following companies meet the criteria of high ROI and low volatility:\n")
for line in formatted_output:
    print(line)
selected_volatility = volatility_all_companies[selected_companies.index]
inverse_volatility = 1 / selected_volatility
 
investment_ratios = inverse_volatility / inverse_volatility.sum()
 
investment_ratios.sort_values(ascending=False)

Analyzing Our Mutual Fund Plan

top_growth_companies = average_growth_all_companies.sort_values(ascending=False).head(10)
risk_growth_rate_companies = volatility_all_companies[top_growth_companies.index]
risk_mutual_fund_companies = volatility_all_companies[selected_companies.index]
 
fig = go.Figure()
 
fig.add_trace(go.Bar(
    y=risk_mutual_fund_companies.index,
    x=risk_mutual_fund_companies,
    orientation='h'# Horizontal bar
    name='Mutual Fund Companies',
    marker=dict(color='blue')
))
 
fig.add_trace(go.Bar(
    y=risk_growth_rate_companies.index,
    x=risk_growth_rate_companies,
    orientation='h',
    name='Growth Rate Companies',
    marker=dict(color='green'),
    opacity=0.7
))
 
fig.update_layout(
    title='Risk Comparison: Mutual Fund vs Growth Rate Companies',
    xaxis_title='Volatility (Standard Deviation)',
    yaxis_title='Companies',
    barmode='overlay',
    legend=dict(title='Company Type'),
    template='plotly_white'
)
 
fig.show()
expected_roi_mutual_fund = roi_all_companies[selected_companies.index]
 
expected_roi_growth_companies = roi_all_companies[top_growth_companies.index]
 
fig = go.Figure()
 
fig.add_trace(go.Bar(
    y=expected_roi_mutual_fund.index,
    x=expected_roi_mutual_fund,
    orientation='h',
    name='Mutual Fund Companies',
    marker=dict(color='blue')
))
 
fig.add_trace(go.Bar(
    y=expected_roi_growth_companies.index,
    x=expected_roi_growth_companies,
    orientation='h',
    name='Growth Rate Companies',
    marker=dict(color='green'),
    opacity=0.7
))
 
fig.update_layout(
    title='Expected ROI Comparison: Mutual Fund vs Growth Rate Companies',
    xaxis_title='Expected ROI (%)',
    yaxis_title='Companies',
    barmode='overlay',
    legend=dict(title='Company Type'),
    template='plotly_white'
)
 
fig.show()
  1. Monthly Investment: Assume the person is investing $60 monthly.
  2. Growth Simulation: Use the expected ROI from mutual fund companies to simulate how this investment might grow over time.
  3. Compounded Value Calculation: Calculate the compounded growth of these monthly investments for each period (1 year, 3 years, 5 years, and 10 years).
  4. Visualization: Present the projected accumulated values for each investment period to provide a clear picture of how the investment might perform over time.
monthly_investment = 500 # Monthly investment in INR
years = [1, 3, 5, 10# Investment periods (in years)
n = 12  # Number of times interest is compounded per year (monthly)
 
avg_roi = expected_roi_mutual_fund.mean() / 100  # Convert to decimal
 
def future_value(P, r, n, t):
    return P * (((1 + r/n)**(n*t) - 1) / (r/n)) * (1 + r/n)
 
future_values = [future_value(monthly_investment, avg_roi, n, t) for t in years]
 
fig = go.Figure()
 
fig.add_trace(go.Scatter(
    x=[str(year) + " year" for year in years],
    y=future_values,
    mode='lines+markers',
    line=dict(color='blue'),
    marker=dict(size=8),
    name='Future Value'
))
 
fig.update_layout(
    title="Expected Value of Investments of 100$ Per Month (Mutual Funds)",
    xaxis_title="Investment Period",
    yaxis_title="Future Value (INR)",
    xaxis=dict(showgrid=True, gridcolor='lightgrey'),
    yaxis=dict(showgrid=True, gridcolor='lightgrey'),
    template="plotly_white",
    hovermode='x'
)
 
fig.show()

Summary


Get your FREE
business consultation

We’re delivering the best
customer experience

Discover More