diff --git a/Investment Portfolio Python Notebook_03_2018_blog example.ipynb b/Investment Portfolio Python Notebook_03_2018_blog example.ipynb index 5db5d2e..511ec28 100644 --- a/Investment Portfolio Python Notebook_03_2018_blog example.ipynb +++ b/Investment Portfolio Python Notebook_03_2018_blog example.ipynb @@ -5829,9 +5829,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 2", + "display_name": "streamlit_apps", "language": "python", - "name": "python2" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -5843,7 +5843,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", - "version": "2.7.13" + "version": "3.12.2" } }, "nbformat": 4, diff --git a/Investment_Portfolio_App.code-workspace b/Investment_Portfolio_App.code-workspace new file mode 100644 index 0000000..517e0b2 --- /dev/null +++ b/Investment_Portfolio_App.code-workspace @@ -0,0 +1,8 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": {} +} \ No newline at end of file diff --git a/New Sheet.xlsx b/New Sheet.xlsx new file mode 100644 index 0000000..04900f9 Binary files /dev/null and b/New Sheet.xlsx differ diff --git a/New_Sheet.xlsx b/New_Sheet.xlsx new file mode 100644 index 0000000..bd04358 Binary files /dev/null and b/New_Sheet.xlsx differ diff --git a/Sample stocks acquisition dates_costs.xlsx b/Sample stocks acquisition dates_costs.xlsx deleted file mode 100644 index 67235a9..0000000 Binary files a/Sample stocks acquisition dates_costs.xlsx and /dev/null differ diff --git a/Updated App.py b/Updated App.py new file mode 100644 index 0000000..08387ad --- /dev/null +++ b/Updated App.py @@ -0,0 +1,149 @@ +# Import initial libraries + +import pandas as pd +import numpy as np +import datetime +import matplotlib.pyplot as plt +import yfinance as yf + + +from plotly import __version__ +from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot + +import plotly.graph_objs as go + +print(__version__) # requires version >= 1.9.0 + +init_notebook_mode(connected=True) + +filepath = "./New Sheet.xlsx" +print("filepath: ", filepath) +# Load the entire Excel file +xls = pd.ExcelFile(filepath) + +# Load all sheet names +sheet_names = xls.sheet_names +print("sheet_names: ", sheet_names) +# Load all sheets into a dictionary of DataFrames +dfs = {sheet: pd.read_excel(xls, sheet) for sheet in sheet_names} + +# Convert the 'Transaction Date' column to datetime format (only year, month, day) in the 'transactions' DataFrame +dfs['Transactions']['Transaction Date'] = pd.to_datetime(dfs['Transactions']['Transaction Date']).dt.date + +# Get unique tickers from the 'Summary' sheet +tickers = dfs['Summary']['Ticker'].unique().tolist() # Convert numpy array to list + +# Fetch today's data for all tickers +data = yf.download(tickers, period='1d') + +# Convert 'Adj Close' DataFrame to a Series +adj_close_series = data['Adj Close'].squeeze() + +# Update the 'Price Today' column in the 'Summary' DataFrame +dfs['Summary']['Price Today'] = dfs['Summary']['Ticker'].map(adj_close_series).round(2) + +# Update the 'Current Value' column in the 'Summary' DataFrame +dfs['Summary']['Current Value'] = dfs['Summary']['Quantity'] * dfs['Summary']['Price Today'].round(3) + +# Update the 'Transaction Total' column in the 'Transactions' DataFrame +dfs['Transactions']['Transaction Total'] = dfs['Transactions']['Shares'] * dfs['Transactions']['Cost Per Share'] + +# Copy the 'Ticker' column from the 'Transactions' DataFrame to the 'Summary' DataFrame +dfs['Summary']['Ticker'] = dfs['Transactions']['Ticker'] + +# Calculate the total quantity for each ticker +quantity_series = dfs['Transactions'].groupby(['Ticker', 'Type'])['Shares'].sum().unstack().fillna(0) +quantity_series['Total'] = quantity_series['Buy'] - quantity_series['Sell'] + +# Update the 'Quantity' column in the 'Summary' DataFrame +dfs['Summary'] = dfs['Summary'].set_index('Ticker') +dfs['Summary']['Quantity'] = quantity_series['Total'] +dfs['Summary'] = dfs['Summary'].reset_index() + +# Calculate the total realized sales for each ticker +realized_sales_series = dfs['Transactions'][dfs['Transactions']['Type'] == 'Sell'].groupby('Ticker')['Transaction Total'].sum() + +# Update the 'Realized Sales' column in the 'Summary' DataFrame +dfs['Summary'] = dfs['Summary'].set_index('Ticker') +dfs['Summary']['Realized Sales'] = realized_sales_series +dfs['Summary'] = dfs['Summary'].reset_index() + +# Sort the 'Transactions' DataFrame by date +dfs['Transactions'] = dfs['Transactions'].sort_values('Transaction Date') + +cost_basis_df = pd.DataFrame(columns=['Ticker', 'Shares', 'Transaction Total']) + +# Initialize a Series to hold the profit for each ticker +profit_series = pd.Series(dtype='float64') + +# Iterate over the sorted 'Transactions' DataFrame +for idx, row in dfs['Transactions'].iterrows(): + if row['Type'] == 'Buy': + # Add the shares to the cost basis DataFrame + cost_basis_df.loc[len(cost_basis_df)] = row[['Ticker', 'Shares', 'Transaction Total']] + elif row['Type'] == 'Sell': + # Subtract the shares from the cost basis DataFrame in the order they were added (FIFO) + sell_shares = row['Shares'] + sell_ticker = row['Ticker'] + sell_price = row['Transaction Total'] / sell_shares + profit = 0 + for i, cost_row in cost_basis_df[cost_basis_df['Ticker'] == sell_ticker].iterrows(): + if sell_shares <= 0: + break + shares_to_sell = min(sell_shares, cost_row['Shares']) + profit += shares_to_sell * (sell_price - (cost_row['Transaction Total'] / cost_row['Shares'])) + sell_shares -= shares_to_sell + cost_basis_df.loc[i, 'Shares'] -= shares_to_sell + cost_basis_df = cost_basis_df[cost_basis_df['Shares'] > 0] + profit_series[sell_ticker] = profit_series.get(sell_ticker, 0) + profit + +# Initialize 'Cost Basis' column in the 'Summary' DataFrame +dfs['Summary']['Cost Basis'] = 0 + +# Convert 'Cost Basis', 'Realized Profit' and 'Unrealized Profit' to float +for column in ['Cost Basis', 'Realized Profit', 'Unrealized Profit']: + dfs['Summary'][column] = dfs['Summary'][column].astype(float) + +# Create a dictionary to hold the cost basis and shares of each ticker +cost_basis_dict = {ticker: [] for ticker in dfs['Summary']['Ticker'].unique()} + +# Iterate over the 'Transactions' DataFrame +for idx, row in dfs['Transactions'].iterrows(): + if row['Type'] == 'Buy': + # Add the transaction total and shares to the cost basis dictionary for the corresponding ticker + cost_basis_dict[row['Ticker']].append((row['Transaction Total'], row['Shares'])) + elif row['Type'] == 'Sell': + # Subtract the cost basis of the sold shares from the cost basis dictionary for the corresponding ticker + sell_shares = row['Shares'] + while sell_shares > 0 and cost_basis_dict[row['Ticker']]: + buy_total, buy_shares = cost_basis_dict[row['Ticker']][0] + if buy_shares > sell_shares: + cost_basis_dict[row['Ticker']][0] = (buy_total * (buy_shares - sell_shares) / buy_shares, buy_shares - sell_shares) + sell_shares = 0 + else: + sell_shares -= buy_shares + cost_basis_dict[row['Ticker']].pop(0) + +# Update the 'Cost Basis' column in the 'Summary' DataFrame +for ticker in dfs['Summary']['Ticker'].unique(): + dfs['Summary'].loc[dfs['Summary']['Ticker'] == ticker, 'Cost Basis'] = sum(total for total, shares in cost_basis_dict[ticker]) + + +# Update the 'Realized Profit' column in the 'Summary' DataFrame +dfs['Summary'] = dfs['Summary'].set_index('Ticker') +dfs['Summary']['Realized Profit'] = profit_series +dfs['Summary'] = dfs['Summary'].reset_index() + +# Calculate 'Unrealized Profit' for each ticker +dfs['Summary']['Unrealized Profit'] = dfs['Summary']['Current Value'] - dfs['Summary']['Cost Basis'] + +# Round 'Cost Basis', 'Realized Profit' and 'Unrealized Profit' to 2 decimal places +for column in ['Cost Basis', 'Realized Profit', 'Unrealized Profit']: + dfs['Summary'][column] = dfs['Summary'][column].round(2) + +# Write all DataFrames back to the Excel file +with pd.ExcelWriter(filepath, engine='openpyxl') as writer: + for sheet, df in dfs.items(): + df.to_excel(writer, sheet_name=sheet, index=False) + + diff --git a/images/NTAI.png b/images/NTAI.png new file mode 100644 index 0000000..4debc67 Binary files /dev/null and b/images/NTAI.png differ diff --git a/investment_portfoli_v2.py b/investment_portfoli_v2.py new file mode 100644 index 0000000..dcc0413 --- /dev/null +++ b/investment_portfoli_v2.py @@ -0,0 +1,134 @@ +""" +Based on the Streamlit Handover Delays Dashboard + +Created on Tue Apr 16 2024 +@author: JL + +""" +import streamlit as st +import time +import pandas as pd +import plotly.express as px +import plotly.graph_objects as go +import subprocess +# import yfinance as yf + +st.set_page_config(page_title='Investment Portfolio App', layout='wide', page_icon=':ambulance:') + +#this is the header + + +# t1, t2 = st.columns((0.07,1)) +t1, t2 = st.columns((0.08,1)) + +t1.image('images/NTAI.png', width = 120) +t2.title("Networking Technology Academy Institute:") +t2.title("\n Personal Investment Portfolio Report") +t2.markdown(" **tel:** 617-123-4567 **| website:** https://www.networktechnologyacademy.org **| email:** xyz@ntai.com") + +dataFile = "New Sheet.xlsx" + +## Data + +with st.spinner('Updating Report...'): + + #Metrics setting and rendering + subprocess.call(["python", "Investment_Portfolio_App.py"]) + invstr_df = pd.read_excel(dataFile,sheet_name = 'Investors') + invstr = st.selectbox('Choose Investor', invstr_df, help = 'Filter report to show only one investor', index = 0) + subprocess.call(["python", "Investment_Portfolio_App.py"]) + # Current Investment Table + cw1, cw2 = st.columns((2.7, 2.5)) + # cwdf = pd.read_excel(dataFile,sheet_name = 'All') + if invstr == 'All': + cwdf = pd.read_excel(dataFile,sheet_name = 'Summary') + elif invstr != 'All': + print("inverstor selected is: ", invstr) + cwdf = pd.read_excel(dataFile,sheet_name = invstr) + + + fig = go.Figure( + data = [go.Table (columnorder = [0,1,2,3,4,5,6,7], columnwidth = [10,20,20,20,20,20,20,20], + header = dict( + values = list(cwdf.columns), + font=dict(size=12, color = 'white'), + fill_color = '#264653', + align = 'center', + height=20 + ) + , cells = dict( + values = [cwdf[K].tolist() for K in cwdf.columns], + font=dict(size=12), + align = 'center', + fill_color='#F0F2F6', + height=20))]) + + fig.update_layout(title_text="Summary",title_font_color = '#264653',title_x=0,margin= dict(l=0,r=10,b=10,t=30), height=480) + + cw1.plotly_chart(fig, use_container_width=True) + + cwdf = pd.read_excel(dataFile,sheet_name = 'Transactions') + if invstr == 'All': + cwdf = cwdf + elif invstr != 'All': + cwdf = cwdf[cwdf['Investor']==invstr] + + + fig = go.Figure( + data = [go.Table (columnorder = [0,1,2,3,4,5,6,7], columnwidth = [25,20,20,20,20,20,20,20], + header = dict( + values = list(cwdf.columns), + font=dict(size=12, color = 'white'), + fill_color = '#264653', + align = 'center', + height=20 + ) + , cells = dict( + values = [cwdf[K].tolist() for K in cwdf.columns], + font=dict(size=12), + align = 'left', + fill_color='#F0F2F6', + height=20))]) + + fig.update_layout(title_text="Transactions",title_font_color = '#264653',title_x=0,margin= dict(l=0,r=10,b=10,t=30), height=480) + + cw2.plotly_chart(fig, use_container_width=True) + + +with st.spinner('Report updated!'): + time.sleep(1) + +# Assume we have a DataFrame +# df = pd.DataFrame({ +# 'A': [1, 2, 3, 4, 5], +# 'B': [10, 20, 30, 40, 50] +# }) + +# row_number = st.number_input('Input row number', min_value=0, max_value=len(df)-1, format="%i") +# column_name = st.selectbox('Select column', df.columns) +# new_value = st.number_input('Input new value', value=df.loc[row_number, column_name]) + +# if st.button('Update Data'): +# df.loc[row_number, column_name] = new_value +# st.write(df) + + +# Contact Form + +with st.expander("Contact us"): + with st.form(key='contact', clear_on_submit=True): + + email = st.text_input('Contact Email') + st.text_area("Query","Please fill in all the information or we may not be able to process your request") + + submit_button = st.form_submit_button(label='Send Information') + + + + + + + + + + \ No newline at end of file diff --git a/investment_portfolio.py b/investment_portfolio.py new file mode 100644 index 0000000..6b5102b --- /dev/null +++ b/investment_portfolio.py @@ -0,0 +1,114 @@ +""" +Based on the Streamlit Handover Delays Dashboard + +Created on Tue Apr 16 2024 +@author: JL + +""" +import streamlit as st +import time +import pandas as pd +import plotly.express as px +import plotly.graph_objects as go + + +st.set_page_config(page_title='Investment Portfolio App', layout='wide', page_icon=':ambulance:') + +#this is the header + +# t1, t2 = st.columns((0.07,1)) +t1, t2 = st.columns((0.08,1)) + +t1.image('images/NTAI.png', width = 120) +t2.title("Networking Technology Academy Institute:") +t2.title("\n Personal Investment Portfolio Report") +t2.markdown(" **tel:** 617-123-4567 **| website:** https://www.networktechnologyacademy.org **| email:** xyz@ntai.com") + +dataFile = "New_Sheet.xlsx" + +## Data Load +with st.spinner('Updating Report...'): + + #Metrics setting and rendering + invstr_df = pd.read_excel(dataFile,sheet_name = 'Investors') + invstr = st.selectbox('Choose Investor', invstr_df, help = 'Filter report to show only one investor') + + # Current Investment Table + cw1, cw2 = st.columns((2.5, 1.7)) + cwdf = pd.read_excel(dataFile,sheet_name = 'Summary') + if invstr == 'All': + cwdf = cwdf + elif invstr != 'All': + cwdf = cwdf[cwdf['Investor']==invstr] + + + fig = go.Figure( + data = [go.Table (columnorder = [0,1,2,3,4,5,6,7,8], columnwidth = [15,20,20,20,20,20,20,20,20], + header = dict( + values = list(cwdf.columns), + font=dict(size=12, color = 'white'), + fill_color = '#264653', + align = 'left', + height=20 + ) + , cells = dict( + values = [cwdf[K].tolist() for K in cwdf.columns], + font=dict(size=12), + align = 'left', + fill_color='#F0F2F6', + height=20))]) + + fig.update_layout(title_text="Summary",title_font_color = '#264653',title_x=0,margin= dict(l=0,r=10,b=10,t=30), height=480) + + cw1.plotly_chart(fig, use_container_width=True) + + cwdf = pd.read_excel(dataFile,sheet_name = 'Transactions') + if invstr == 'All': + cwdf = cwdf + elif invstr != 'All': + cwdf = cwdf[cwdf['Investor']==invstr] + + + fig = go.Figure( + data = [go.Table (columnorder = [0,1,2,3,4,5,6], columnwidth = [15,20,20,20,20,20,20], + header = dict( + values = list(cwdf.columns), + font=dict(size=12, color = 'white'), + fill_color = '#264653', + align = 'left', + height=20 + ) + , cells = dict( + values = [cwdf[K].tolist() for K in cwdf.columns], + font=dict(size=12), + align = 'left', + fill_color='#F0F2F6', + height=20))]) + + fig.update_layout(title_text="Transactions",title_font_color = '#264653',title_x=0,margin= dict(l=0,r=10,b=10,t=30), height=480) + + cw2.plotly_chart(fig, use_container_width=True) + + +with st.spinner('Report updated!'): + time.sleep(1) + + +# Contact Form +with st.expander("Contact us"): + with st.form(key='contact', clear_on_submit=True): + + email = st.text_input('Contact Email') + st.text_area("Query","Please fill in all the information or we may not be able to process your request") + + submit_button = st.form_submit_button(label='Send Information') + + + + + + + + + + \ No newline at end of file