CapiPort / utilities /py /composer.py
Carsten Stahl
found better name for composer
cf46b3a
import pandas as pd
import streamlit as st
from utilities.py.data_management import CompData, PortfolioOptimizer
from utilities.py.ui_elements import UserInput
from utilities.py import plots, summary_tables
class CapiPortApp:
def __init__(self, company_df):
"""
Class for composing the apps UI on a high level. Is meant to provide a readable overview, of what happens inside the app, without being concerned with unnecessary details.
Uppon initializing the composer fetches the data within the apps source code (for now) and let's a dedicated class handle the raw data.
"""
self.comp_data = CompData(company_df)
# get all the necessary ui elements
self.user_input = UserInput(self.comp_data)
def render_user_input(self):
self.user_input.company_selection()
self.user_input.opt_method_selection()
self.user_input.start_date()
self.user_input.initial_investment()
def render_results(self):
"""
CAUTION: the composer assumes, that the user has given all the necessary data.
NECESSARY DATA:
- at least two companies
- an optimization method
- a start date
- initial investment
Check the conditions the necessary conditions beforehand :)
"""
# fetch user input
user_input_data = self.user_input.get_user_input_data()
# optimize the chosen portfolio according to the specifications
portfolio_opt = PortfolioOptimizer(self.comp_data,
self.user_input.get_selected_comp_ids(),
user_input_data.start_date)
company_asset_weights = portfolio_opt.optimize(user_input_data.opt_method,
user_input_data.ef_parameter)
# show first the stock data...
st.dataframe(portfolio_opt.stock_data, use_container_width=True)
# print disclaimer
first_date_available = portfolio_opt.stock_data.index[0]
opt_header = f"Used {user_input_data.opt_method}" if user_input_data.ef_parameter is None else f"Used {user_input_data.opt_method} with {user_input_data.ef_parameter}"
st.write(
f"Note: Due to unavailability of full data, this Analysis uses data from the date: {first_date_available}")
st.write(opt_header)
# show asset weights, portfolio performance and the pie chart
st.dataframe(company_asset_weights, use_container_width=True)
st.dataframe(portfolio_opt.get_portfolio_performance(),
use_container_width=True)
plots.pie_chart_company_asset_weights(company_asset_weights)
# summarize the resulting data
portfolio_returns = portfolio_opt.get_portfolio_returns()
annual_portfolio_returns = portfolio_opt.get_annual_portfolio_returns()
cumulative_returns = (portfolio_returns +
1).cumprod() * user_input_data.init_invest
# render the tabs
tab1, tab2, tab3 = st.tabs(
["Plots", "Annual Returns", "Montly Returns"])
with tab1:
plots.plot_annual_returns(annual_portfolio_returns)
plots.plot_cummulative_returns(cumulative_returns)
with tab2:
annual_portfolio_returns = summary_tables.annual_returns_dataframe(
annual_portfolio_returns
)
annual_cumulative_returns = (
summary_tables.annual_cumulative_returns_dataframe(
cumulative_returns)
)
annual_stock_returns = summary_tables.company_wise_annual_return(
portfolio_opt.stock_data_returns, company_asset_weights
)
merged_annual_returns_data = pd.merge(
annual_portfolio_returns,
annual_cumulative_returns,
on="Year",
suffixes=("_portfolio", "_cumulative"),
)
merged_annual_returns_data = pd.merge(
merged_annual_returns_data, annual_stock_returns, on="Year"
)
st.write("Annual Returns")
st.dataframe(merged_annual_returns_data, use_container_width=True)
with tab3:
monthly_portfolio_return = summary_tables.monthly_returns_dataframe(
portfolio_returns
)
monthly_stock_return = summary_tables.company_wise_monthly_return(
portfolio_opt.stock_data_returns, company_asset_weights
)
monthly_cumulative_returns = (
summary_tables.monthly_cumulative_returns_dataframe(
cumulative_returns)
)
merged_monthly_returns_data = pd.merge(
monthly_portfolio_return,
monthly_cumulative_returns,
on=["Year", "Month"],
how="inner",
)
merged_monthly_returns_data = pd.merge(
merged_monthly_returns_data,
monthly_stock_return,
on=["Year", "Month"],
how="inner",
)
st.write("Montly Return")
st.dataframe(merged_monthly_returns_data, use_container_width=True)