Skip to content

Commit

Permalink
added chart and optimization
Browse files Browse the repository at this point in the history
  • Loading branch information
MarekOzana committed Aug 18, 2024
1 parent 9d05ce1 commit bd0fa86
Showing 1 changed file with 81 additions and 31 deletions.
112 changes: 81 additions & 31 deletions pages/Micro_Finance_Analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,46 @@
"""

import logging
import streamlit as st
import pandas as pd
from pathlib import Path

# import sys
# import os
import numpy as np
import pandas as pd
import polars as pl
import streamlit as st
from scipy.stats import norm

# # Add the src directory to the sys.path
# sys.path.append(os.path.abspath(os.path.join(os.getcwd(), "src")))
# import optimization as opt
import src.charts as charts
import src.optimization as opt

st.set_page_config(
page_title="SEB Micro Finance Analyser",
layout="wide",
page_icon="💸",
)

logger: logging.Logger = logging.getLogger(__name__)


def load_data() -> None:
if "corr" in st.session_state:
logger.debug("ignoring load_data because data already exist")
return

logger.info("Reading in data and calculating params")
rets = pd.read_csv("data/micfin_q_rets.csv", index_col=0, parse_dates=True)
st.session_state["orig_rets"] = rets

exp_rets = pd.read_csv("data/micfin_exp_rets.csv", index_col=0).squeeze()
st.session_state["orig_exp_rets"] = exp_rets

vols = rets.std() * 2 # * sqrt(4) for quarterly
vols.name = "Vol"
st.session_state["orig_vols"] = vols

corr = rets.corr()
st.session_state["orig_corr"] = corr.round(2)


def get_user_input() -> None:
with st.sidebar:
st.title("Parameters")
Expand All @@ -37,6 +62,15 @@ def get_user_input() -> None:
)
st.session_state["r_min"] = r_min

all_tickers = st.session_state["orig_corr"].columns.tolist()
tickers = st.multiselect(
label="Tickers",
options=all_tickers,
default=all_tickers[:-1],
help="Select Tickers for the optimization",
)
st.session_state["tickers"] = tickers

with st.popover("Exp Returns"):
exp_rets = st.data_editor(
st.session_state["orig_exp_rets"] * 100,
Expand Down Expand Up @@ -75,33 +109,49 @@ def get_user_input() -> None:
st.session_state["corr"] = corr.div(100)


def load_data() -> None:
if "corr" in st.session_state:
logger.info("ignoring load_data because data already exist")
return

logger.info("Reading in data and calculating params")
rets = pd.read_csv("data/micfin_q_rets.csv", index_col=0, parse_dates=True)
st.session_state["orig_rets"] = rets

exp_rets = pd.read_csv("data/micfin_exp_rets.csv", index_col=0).squeeze()
st.session_state["orig_exp_rets"] = exp_rets

vols = rets.std() * 2 # * sqrt(4) for quarterly
vols.name = "Vol"
st.session_state["orig_vols"] = vols

corr = rets.corr()
st.session_state["orig_corr"] = corr.round(2)


def main() -> None:
st.title("Micro Finance Analyzer")
load_data()
load_data() # Just once

get_user_input()
st.dataframe(st.session_state["corr"])
st.dataframe(st.session_state["exp_rets"])
st.dataframe(st.session_state["vols"])

# get covar and calculate optimal portfolio
tickers = st.session_state["tickers"]
vols = st.session_state["vols"].loc[tickers]
corr = st.session_state["corr"].loc[tickers, tickers]
vol_d = np.diag(vols.values)
cov = vol_d @ corr.values @ vol_d
exp_rets = st.session_state["exp_rets"].loc[tickers]
r_min = st.session_state["r_min"]
w, r_opt, vol_opt = opt.find_min_var_portfolio(exp_rets, cov, r_min)

# Create Scatter chart and Portfolio Composition Chart
g_data = pl.DataFrame(
{
"name": tickers + ["OPTIMAL"],
"vols": vols.to_list() + [vol_opt],
"rets": exp_rets.to_list() + [r_opt],
"w_opt": w.tolist() + [1],
}
)
f_sc = charts.create_scatter_chart(g_data, None)
f_w = charts.create_portf_weights_chart(g_data)
title = f"Optimal Portfolio: r={r_opt:0.1%}, vol={vol_opt:0.1%}"
col1, col2 = st.columns([1.5, 1])
col1.altair_chart(f_sc, use_container_width=True)
col2.altair_chart(f_w.properties(title=title, height=350), use_container_width=True)
st.markdown(
f"""
### Optimal Portfolio Statistics
* **Expected Return in 1y** = {r_opt:0.1%}
* **Expected volatility** = {vol_opt:0.1%}
* 95%-prob Lowest Expected Return in 1y = {(r_opt - norm.ppf(0.95)*vol_opt):0.1%}
* 99%-prob Lowest Expected Return in 1y = {(r_opt - norm.ppf(0.99)*vol_opt):0.1%}
"""
)

st.divider()
st.caption(Path("data/disclaimer.txt").read_text())


# Entry point for the script
Expand Down

0 comments on commit bd0fa86

Please sign in to comment.