diff --git "a/src/pages/1_\360\237\223\210_Basic_Stats.py" "b/src/pages/1_\360\237\223\210_Basic_Stats.py"
index fe9e18d..60885bf 100644
--- "a/src/pages/1_\360\237\223\210_Basic_Stats.py"
+++ "b/src/pages/1_\360\237\223\210_Basic_Stats.py"
@@ -5,6 +5,7 @@
PLT_CONFIG,
PLT_CONFIG_NO_LOGO,
FAVICON,
+ DICT_GROUPBY_LEVELS,
)
from utils import (
aggregate_by_ticker,
@@ -86,16 +87,11 @@
options=["Macro Asset Classes", "Asset Classes", "Ticker"],
horizontal=True,
)
- dict_group_by = {
- "Macro Asset Classes": "macro_asset_class",
- "Asset Classes": "asset_class",
- "Ticker": "ticker",
- }
df_pivot_ = get_portfolio_pivot(
df=df_j,
df_dimensions=df_anagrafica,
pf_actual_value=pf_actual_value,
- aggregation_level=dict_group_by[group_by],
+ aggregation_level=DICT_GROUPBY_LEVELS[group_by],
)
df_pivot_.index += 1
st.table(
diff --git "a/src/pages/2_\360\237\221\251\342\200\215\360\237\224\254_Advanced_Stats.py" "b/src/pages/2_\360\237\221\251\342\200\215\360\237\224\254_Advanced_Stats.py"
index 8962143..330e8af 100644
--- "a/src/pages/2_\360\237\221\251\342\200\215\360\237\224\254_Advanced_Stats.py"
+++ "b/src/pages/2_\360\237\221\251\342\200\215\360\237\224\254_Advanced_Stats.py"
@@ -1,17 +1,14 @@
import streamlit as st
-from var import (
- GLOBAL_STREAMLIT_STYLE,
- # PLT_CONFIG,
- # PLT_CONFIG_NO_LOGO,
- FAVICON,
+from var import GLOBAL_STREAMLIT_STYLE, PLT_CONFIG_NO_LOGO, FAVICON, DICT_GROUPBY_LEVELS
+
+from utils import (
+ get_max_common_history,
+ write_disclaimer,
+ get_daily_returns,
)
-# from utils import (
-# sharpe_ratio,
-# get_risk_free_rate_last_value,
-# get_risk_free_rate_history,
-# )
+from plot import plot_correlation_map
st.set_page_config(
page_title="PFN | Advanced Stats",
@@ -21,15 +18,70 @@
)
st.markdown(GLOBAL_STREAMLIT_STYLE, unsafe_allow_html=True)
-st.warning("Work in progress! Please, come back later", icon="🚧")
-# df_common_history = get_max_common_history(ticker_list=ticker_list)
+if "data" in st.session_state:
+ df_transactions = st.session_state["data"]
+ df_registry = st.session_state["dimensions"]
+else:
+ st.error("Oops... there's nothing to display. Go through 🏠 first to load the data")
+ st.stop()
+
+ticker_list = df_transactions["ticker_yf"].unique().tolist()
+df_common_history = get_max_common_history(ticker_list=ticker_list)
+
+st.markdown("## Correlation of daily returns")
+
+col_l_up, col_r_up = st.columns([1, 1], gap="small")
+
+level = col_l_up.radio(
+ label="Aggregate by:",
+ options=["Macro Asset Classes", "Asset Classes", "Ticker"],
+ horizontal=True,
+ index=2,
+)
+
+enhance_corr = col_r_up.radio(
+ "Kind of correlation to enhance:",
+ options=["Positive", "Null", "Negative"],
+ horizontal=True,
+)
+
+st.markdown("")
+col_l_mid, col_r_mid = st.columns([1, 0.3], gap="small")
-# weights = [
-# df_pivot[df_pivot["ticker_yf"].eq(x_)]["weight_pf"].values[0]
-# for x_ in df_common_history.columns
-# ]
-# weighted_average = pd.Series(np.average(df_common_history, weights=weights, axis=1))
+first_transaction = df_transactions["transaction_date"].sort_values().values[0]
+first_day, last_day = col_l_mid.select_slider(
+ "Select a time slice:",
+ options=df_common_history.index,
+ value=[first_transaction, df_common_history.index[-1]],
+ format_func=lambda value: str(value)[:10],
+ label_visibility="collapsed",
+)
+
+df_daily_rets = get_daily_returns(
+ df=df_common_history.loc[first_day:last_day, :],
+ df_registry=df_registry,
+ level=DICT_GROUPBY_LEVELS[level],
+)
+
+fig = plot_correlation_map(
+ df=df_daily_rets.corr(),
+ enhance_correlation=enhance_corr.lower(),
+ lower_triangle_only=True,
+)
+st.plotly_chart(fig, use_container_width=True, config=PLT_CONFIG_NO_LOGO)
+
+# st.markdown("## Distribution of Daily Returns")
+
+# diff_prev_day = get_wealth_history(
+# df_transactions=df_transactions,
+# df_prices=get_max_common_history(ticker_list=ticker_list),
+# )['diff_previous_day']
+
+# import plotly.express as px
+# st.plotly_chart(px.histogram(diff_prev_day), use_container_width=True, config=PLT_CONFIG_NO_LOGO)
+
+#################################
# returns = np.log(weighted_average.div(weighted_average.shift(1))).fillna(0)
@@ -46,3 +98,5 @@
# )
# st.write(sr)
+
+write_disclaimer()
diff --git a/src/plot.py b/src/plot.py
index 9b88d0f..488d327 100644
--- a/src/plot.py
+++ b/src/plot.py
@@ -53,11 +53,11 @@ def plot_pnl_by_asset_class(
def plot_wealth(df: pd.DataFrame) -> go.Figure:
fig = px.area(
- data_frame=df,
- x=df.index,
- y="ap_daily_value",
+ data_frame=df, x=df.index, y="ap_daily_value", custom_data=["diff_previous_day"]
+ )
+ fig.update_traces(
+ hovertemplate="%{x}: %{y:,.0f}€ Gain/Loss on previous day: %{customdata:,.0f}€"
)
- fig.update_traces(hovertemplate="%{x}: %{y:,.0f}€")
fig.update_layout(
autosize=False,
height=550,
@@ -70,3 +70,45 @@ def plot_wealth(df: pd.DataFrame) -> go.Figure:
showlegend=False,
)
return fig
+
+
+def plot_correlation_map(
+ df: pd.DataFrame,
+ enhance_correlation: Literal["positive", "null", "negative"],
+ lower_triangle_only: bool = False,
+):
+ if lower_triangle_only:
+ mask = np.triu(np.ones_like(df, dtype=bool))
+
+ if enhance_correlation == "positive":
+ cuts = [-1, 0, 1]
+ colors = ["white", "white", "darkred"]
+ elif enhance_correlation == "null":
+ cuts = [-1, -0.3, 0, 0.3, 1]
+ colors = ["white", "white", "darkgreen", "white", "white"]
+ elif enhance_correlation == "negative":
+ cuts = [-1, 0, 1]
+ colors = ["darkblue", "white", "white"]
+ colorscale = [[(cut_ + 1) / 2, col_] for cut_, col_ in zip(cuts, colors)]
+
+ fig = go.Figure(
+ go.Heatmap(
+ z=df.mask(mask) if lower_triangle_only else df,
+ x=df.columns,
+ y=df.columns,
+ colorscale=colorscale,
+ zmin=-1,
+ zmax=1,
+ )
+ )
+ fig.update_traces(hovertemplate="%{z:.2f} ")
+ fig.update_layout(
+ height=500,
+ hoverlabel_font_size=PLT_FONT_SIZE,
+ margin=dict(l=0, r=0, t=30, b=0),
+ yaxis=dict(autorange="reversed", showgrid=False),
+ # paper_bgcolor="rgba(0,0,0,0)",
+ # plot_bgcolor="rgba(0,0,0,0)",
+ )
+
+ return fig
diff --git a/src/utils.py b/src/utils.py
index 60c6180..3531ef5 100644
--- a/src/utils.py
+++ b/src/utils.py
@@ -274,12 +274,14 @@ def get_wealth_history(
df_asset_allocation.loc[data, ticker] += total_shares
df_asset_allocation = df_asset_allocation.cumsum()
- df_wealth = (
+ df_wealth = pd.DataFrame(
df_asset_allocation.multiply(df_prices.loc[begin_date:])
.fillna(method="ffill")
.sum(axis=1)
.rename("ap_daily_value")
)
+ df_wealth["diff_previous_day"] = df_wealth.diff()
+
return df_wealth
@@ -341,3 +343,25 @@ def write_disclaimer() -> None:
',
unsafe_allow_html=True,
)
+
+
+@st.cache_data(ttl=CACHE_EXPIRE_SECONDS, show_spinner=False)
+def get_daily_returns(
+ df: pd.DataFrame,
+ df_registry: pd.DataFrame,
+ level: Literal["ticker", "asset_class", "macro_asset_class"],
+):
+ df_daily_rets = df.pct_change()[1:]
+
+ if level == "ticker":
+ return df_daily_rets
+ else:
+ classes = df_registry[level].unique()
+ df_daily_rets_classes = pd.DataFrame(columns=classes)
+ for class_ in classes:
+ cols_to_sum = df_registry[df_registry[level].eq(class_)][
+ "ticker_yf"
+ ].to_list()
+
+ df_daily_rets_classes[class_] = df_daily_rets[cols_to_sum].sum(axis=1)
+ return df_daily_rets_classes
diff --git a/src/var.py b/src/var.py
index b20e76e..8f5fb52 100644
--- a/src/var.py
+++ b/src/var.py
@@ -8,7 +8,7 @@
os.path.join(*split_script_running_path[0 : len(split_script_running_path) - 1])
)
-APP_VERSION = "0.1.0"
+APP_VERSION = "0.1.1"
# Data/images
@@ -44,3 +44,8 @@
# Others
TRADING_DAYS_YEAR = 252
+DICT_GROUPBY_LEVELS = {
+ "Macro Asset Classes": "macro_asset_class",
+ "Asset Classes": "asset_class",
+ "Ticker": "ticker",
+}