Skip to content

Commit

Permalink
added correlation ehancment
Browse files Browse the repository at this point in the history
  • Loading branch information
ggsmith842 committed Jul 29, 2023
1 parent 70d92bc commit 5b103ee
Show file tree
Hide file tree
Showing 6 changed files with 213 additions and 391 deletions.
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"[python]": {
"editor.defaultFormatter": "ms-python.black-formatter"
"editor.defaultFormatter": "ms-python.python"
},
"python.formatting.provider": "none",
"python.linting.enabled": false
Expand Down
471 changes: 101 additions & 370 deletions examples/Portfolio Correlation.ipynb

Large diffs are not rendered by default.

56 changes: 54 additions & 2 deletions src/correlation.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,63 @@
calculations.
"""
#!/usr/bin/env python
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns


def findcorr():
def findcorr(price_data):
"""
Finds the weighed correlation of assets
in a portfolio.
Args:
price_data (DataFrame): A DataFrame of asset prices.
Returns:
None.
"""
return 0
price_data.fillna(0, inplace=True)
corr_df = price_data.corr(method="pearson", numeric_only=True)

# grab bottom half
mask = np.zeros_like(corr_df)
mask[np.triu_indices_from(mask)] = True

# plot correlations
plt.figure(figsize=(8, 6))
sns.heatmap(
corr_df,
annot=True,
cmap="RdYlGn",
vmax=1.0,
vmin=-1.0,
mask=mask,
linewidths=2.5,
)
plt.show()

avg_corr = corr_df.mean()

report = format_report(avg_corr)
print(report)

def format_report(avg_corr):
'''
Formats a diversification report based on the correlation
of assets in a given portfolio.
Args:
avg_corr (Series): A series of asset correlations.
Returns:
report (String): Formatted text reporting correlation
'''
header = "Diversification Report for Portfolio\n"
divider = "-"*len(header)
asset_mean = f"\nMean Correlation of each asset:\n{avg_corr.to_string(index=False)}\n"
avg_mean = f"\nAverage Correlation of Portfolio\n{avg_corr.mean():.3f}"

report = header + divider + asset_mean + divider + avg_mean
return report
43 changes: 34 additions & 9 deletions src/dataloader.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,58 @@
"""
Utility module to load data into a sqlite3 database
Utility module to load data into a sqlite3 database.
This module provides a function to load pricing data into a sqlite3 database.
The function takes a portfolio of ticker symbols as input and a period of time as input.
The function then downloads the pricing data for the portfolio from
Yahoo Finance and loads it into a sqlite3 database.
The module also provides a main function that can be used to test the function.
"""

#!/usr/bin/env python #
import sqlite3
import yfinance as yf


def data_loader(portfolio, period="10yr"):
def data_loader(portfolio, period="5y", tosqlite=False):
"""
Helper function to load pricing data into
a sqllite3 database.
Args:
portfolio (list): A list of ticker symbols.
period (str, optional): The period of time for the pricing data. Defaults to "10y".
period values: “1d”, “5d”, “1mo”, “3mo”, “6mo”, “1y”, “2y”, “5y”, “10y”, “ytd”, “max”
tosqlite (bool, optional): Load the data into a sqlite3 database. Defaults to False.
Returns:
DataFrame: The pricing data for the portfolio only if tosqlite is False.
"""

data = yf.download(portfolio, group_by="Ticker", period=period)
data = data.iloc[:, data.columns.get_level_values(1) == "Close"]
data = data.dropna()
data.columns = data.columns.droplevel(1)

# Create sqlite database connection object
conn = sqlite3.connect("sqlite3.db")
if tosqlite:
# Create sqlite database connection object
try:
conn = sqlite3.connect("advisor_db.db")
except sqlite3.OperationalError:
conn = sqlite3.connect("advisor_db.db")
conn.execute("CREATE TABLE prices (date DATE, ticker TEXT, close FLOAT)")

# Write dataframe to a table in sqlite database
data.to_sql("Prices", conn, if_exists="append", index=False)
# Write dataframe to a table in sqlite database
data.to_sql("prices", conn, if_exists="replace", index=False)

# Close connection object
conn.close()
# Close connection object
conn.close()
else:
return data.reset_index()


if __name__ == "__main__":
portfolio_string = ["SPY WMT JNPR CVS BAC JNJ ABBNY SHEL ORCL"]
portfolio_string = ["SPY WMT JNPR CVS BAC JNJ ABBNY SHEL ORCL USRT"]
data_loader(portfolio=portfolio_string)
3 changes: 1 addition & 2 deletions src/projections.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import pandas as pd

import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
from matplotlib import ticker


class Projection:
Expand Down Expand Up @@ -86,7 +86,6 @@ def visualize(self, target_amount: float = 0.0):

scale_y = 1e6
ticks_y = ticker.FuncFormatter(lambda x, pos: f"{x / scale_y:g}")
# ticks_y = ticker.FuncFormatter(lambda x, pos: "{0:g}".format(x / scale_y))
fig, ax = plt.subplots()
ax.yaxis.set_major_formatter(ticks_y)
ax.set_ylabel("Millions (USD)")
Expand Down
29 changes: 22 additions & 7 deletions src/pyportfolio.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from pypfopt.efficient_frontier import EfficientFrontier

import numpy as np
from correlation import findcorr


class Allocation:
Expand Down Expand Up @@ -42,12 +43,12 @@ def __init__(
self.expected_return = expected_return
self.allocations = []

price_df = self.__get_daily_prices(ticker_string, "20y")
self.price_df = self.__get_daily_prices(ticker_string, "20y")

self.mu = expected_returns.mean_historical_return(price_df)
self.S = risk_models.sample_cov(price_df)
self.mu_return = expected_returns.mean_historical_return(self.price_df)
self.sample_covr = risk_models.sample_cov(self.price_df)

self.efficient_frontier = EfficientFrontier(self.mu, self.S)
self.efficient_frontier = EfficientFrontier(self.mu_return, self.sample_covr)

self.efficient_frontier.efficient_return(expected_return)
self.expected_risk = self.efficient_frontier.portfolio_performance()[1]
Expand Down Expand Up @@ -133,10 +134,10 @@ def show_efficient_frontier(self):
Returns:
None
"""
efficient_frontier = EfficientFrontier(self.mu, self.S)
efficient_frontier = EfficientFrontier(self.mu_return, self.sample_covr)
_, ax = plt.subplots()
ef_max_sharpe = EfficientFrontier(self.mu, self.S)
ef_return = EfficientFrontier(self.mu, self.S)
ef_max_sharpe = EfficientFrontier(self.mu_return, self.sample_covr)
ef_return = EfficientFrontier(self.mu_return, self.sample_covr)
plotting.plot_efficient_frontier(efficient_frontier, ax=ax, show_assets=False)
n_samples = 10000
weights = np.random.dirichlet(np.ones(efficient_frontier.n_assets), n_samples)
Expand All @@ -157,3 +158,17 @@ def show_efficient_frontier(self):
ax.legend()
plt.tight_layout()
plt.show()

def correlation_report(self):
"""
Finds the weighed correlation of assets
in a portfolio.
Args:
price_data (DataFrame): A DataFrame of asset prices.
Returns:
None.
"""
return findcorr(price_data=self.price_df)

0 comments on commit 5b103ee

Please sign in to comment.