Add sheetnames and improve mret

This commit is contained in:
jeroen
2023-02-06 13:28:51 +01:00
parent 648a83f9d5
commit c6aadac1d8
3 changed files with 177 additions and 37 deletions

View File

@@ -1004,6 +1004,23 @@ class PortfolioController(BaseController):
help="Period to select start end of the year returns",
metavar="PERIOD",
)
parser.add_argument(
"-i",
"--instrument",
type=str,
dest="instrument",
default="both",
choices=["both", "portfolio", "benchmark"],
help="Whether to show portfolio or benchmark monthly returns. By default both are shown in one table.",
)
parser.add_argument(
"-g",
"--graph",
action="store_true",
default=False,
dest="graph",
help="Plot the monthly returns on a heatmap",
)
parser.add_argument(
"-s",
"--show",
@@ -1018,7 +1035,7 @@ class PortfolioController(BaseController):
parser,
other_args,
raw=True,
export_allowed=EXPORT_ONLY_FIGURES_ALLOWED,
export_allowed=EXPORT_ONLY_RAW_DATA_ALLOWED,
)
if ns_parser and self.portfolio is not None:
@@ -1028,10 +1045,13 @@ class PortfolioController(BaseController):
portfolio_view.display_monthly_returns(
self.portfolio,
ns_parser.period,
ns_parser.raw,
ns_parser.instrument,
ns_parser.graph,
ns_parser.show_vals,
ns_parser.export,
ns_parser.sheet_name,
sheet_name=" ".join(ns_parser.sheet_name)
if ns_parser.sheet_name
else None,
)
@log_start_end(log=logger)
@@ -1073,7 +1093,9 @@ class PortfolioController(BaseController):
ns_parser.raw,
ns_parser.limit,
ns_parser.export,
ns_parser.sheet_name,
sheet_name=" ".join(ns_parser.sheet_name)
if ns_parser.sheet_name
else None,
)
@log_start_end(log=logger)
@@ -1095,9 +1117,6 @@ class PortfolioController(BaseController):
portfolio_view.display_maximum_drawdown(
self.portfolio,
export=ns_parser.export,
sheet_name=" ".join(ns_parser.sheet_name)
if ns_parser.sheet_name
else None,
)
@log_start_end(log=logger)
@@ -1331,18 +1350,26 @@ class PortfolioController(BaseController):
self.portfolio,
ns_parser.risk_free_rate / 100,
ns_parser.export,
ns_parser.sheet_name,
sheet_name=" ".join(ns_parser.sheet_name)
if ns_parser.sheet_name
else None,
)
elif ns_parser.metric == "sortino":
portfolio_view.display_sortino_ratio(
self.portfolio,
ns_parser.risk_free_rate / 100,
ns_parser.export,
ns_parser.sheet_name,
sheet_name=" ".join(ns_parser.sheet_name)
if ns_parser.sheet_name
else None,
)
elif ns_parser.metric == "maxdrawdown":
portfolio_view.display_maximum_drawdown_ratio(
self.portfolio, ns_parser.export, ns_parser.sheet_name
self.portfolio,
ns_parser.export,
sheet_name=" ".join(ns_parser.sheet_name)
if ns_parser.sheet_name
else None,
)
elif ns_parser.metric == "rsquare":
portfolio_view.display_rsquare(
@@ -1354,15 +1381,27 @@ class PortfolioController(BaseController):
)
elif ns_parser.metric == "gaintopain":
portfolio_view.display_gaintopain_ratio(
self.portfolio, ns_parser.export, ns_parser.sheet_name
self.portfolio,
ns_parser.export,
sheet_name=" ".join(ns_parser.sheet_name)
if ns_parser.sheet_name
else None,
)
elif ns_parser.metric == "trackerr":
portfolio_view.display_tracking_error(
self.portfolio, ns_parser.export, ns_parser.sheet_name
self.portfolio,
ns_parser.export,
sheet_name=" ".join(ns_parser.sheet_name)
if ns_parser.sheet_name
else None,
)
elif ns_parser.metric == "information":
portfolio_view.display_information_ratio(
self.portfolio, ns_parser.export, ns_parser.sheet_name
self.portfolio,
ns_parser.export,
sheet_name=" ".join(ns_parser.sheet_name)
if ns_parser.sheet_name
else None,
)
elif ns_parser.metric == "tail":
portfolio_view.display_tail_ratio(
@@ -1374,30 +1413,52 @@ class PortfolioController(BaseController):
)
elif ns_parser.metric == "commonsense":
portfolio_view.display_common_sense_ratio(
self.portfolio, ns_parser.export, ns_parser.sheet_name
self.portfolio,
ns_parser.export,
sheet_name=" ".join(ns_parser.sheet_name)
if ns_parser.sheet_name
else None,
)
elif ns_parser.metric == "jensens":
portfolio_view.display_jensens_alpha(
self.portfolio,
ns_parser.risk_free_rate / 100,
ns_parser.export,
ns_parser.sheet_name,
sheet_name=" ".join(ns_parser.sheet_name)
if ns_parser.sheet_name
else None,
)
elif ns_parser.metric == "calmar":
portfolio_view.display_calmar_ratio(
self.portfolio, ns_parser.export, ns_parser.sheet_name
self.portfolio,
ns_parser.export,
sheet_name=" ".join(ns_parser.sheet_name)
if ns_parser.sheet_name
else None,
)
elif ns_parser.metric == "kelly":
portfolio_view.display_kelly_criterion(
self.portfolio, ns_parser.export, ns_parser.sheet_name
self.portfolio,
ns_parser.export,
sheet_name=" ".join(ns_parser.sheet_name)
if ns_parser.sheet_name
else None,
)
elif ns_parser.metric == "payoff" and self.portfolio is not None:
portfolio_view.display_payoff_ratio(
self.portfolio, ns_parser.export, ns_parser.sheet_name
self.portfolio,
ns_parser.export,
sheet_name=" ".join(ns_parser.sheet_name)
if ns_parser.sheet_name
else None,
)
elif ns_parser.metric == "profitfactor" and self.portfolio is not None:
portfolio_view.display_profit_factor(
self.portfolio, ns_parser.export, ns_parser.sheet_name
self.portfolio,
ns_parser.export,
sheet_name=" ".join(ns_parser.sheet_name)
if ns_parser.sheet_name
else None,
)
@log_start_end(log=logger)
@@ -1437,7 +1498,9 @@ class PortfolioController(BaseController):
ns_parser.period,
ns_parser.raw,
ns_parser.export,
ns_parser.sheet_name,
sheet_name=" ".join(ns_parser.sheet_name)
if ns_parser.sheet_name
else None,
)
@log_start_end(log=logger)
@@ -1484,7 +1547,9 @@ class PortfolioController(BaseController):
ns_parser.period,
ns_parser.risk_free_rate / 100,
ns_parser.export,
ns_parser.sheet_name,
sheet_name=" ".join(ns_parser.sheet_name)
if ns_parser.sheet_name
else None,
)

View File

@@ -371,7 +371,36 @@ def get_monthly_returns(
],
)
return monthly_returns, bench_monthly_returns
years = [
(year, instrument)
for year in monthly_returns.index
for instrument in ["Portfolio", "Benchmark", "Alpha"]
]
total_monthly_returns = pd.DataFrame(
np.nan,
columns=monthly_returns.columns,
index=pd.MultiIndex.from_tuples(years, names=["Year", "Instrument"]),
)
for year in monthly_returns.index:
for instrument in ["Portfolio", "Benchmark", "Alpha"]:
if instrument == "Portfolio":
total_monthly_returns.loc[
(year, instrument), monthly_returns.columns
] = monthly_returns.loc[year].values
elif instrument == "Benchmark":
total_monthly_returns.loc[
(year, instrument), monthly_returns.columns
] = bench_monthly_returns.loc[year].values
elif instrument == "Alpha":
total_monthly_returns.loc[
(year, instrument), monthly_returns.columns
] = (
monthly_returns.loc[year].values
- bench_monthly_returns.loc[year].values
)
return monthly_returns, bench_monthly_returns, total_monthly_returns
@log_start_end(log=logger)

View File

@@ -475,7 +475,8 @@ def display_yearly_returns(
def display_monthly_returns(
portfolio_engine: PortfolioEngine,
window: str = "all",
raw: bool = False,
instrument: str = "both",
graph: bool = False,
show_vals: bool = False,
export: str = "",
sheet_name: str = None,
@@ -490,27 +491,38 @@ def display_monthly_returns(
Use `portfolio.load` to create a PortfolioEngine.
window : str
interval to compare cumulative returns and benchmark
raw : False
Display raw data from cumulative return
instrument : str
Display raw data from cumulative return, default is showing both the portfolio and benchmark in one table
show_vals : False
Show values on heatmap
export : str
Export certain type of data
sheet_name : str
Whether to export to a specific sheet name in an Excel file
external_axes: plt.Axes
Optional axes to display plot on
"""
portfolio_returns, benchmark_returns = get_monthly_returns(portfolio_engine, window)
portfolio_returns, benchmark_returns, total_monthly_returns = get_monthly_returns(
portfolio_engine, window
)
if raw:
if instrument == "portfolio":
print_rich_table(
portfolio_returns,
title="Monthly returns - portfolio [%]",
headers=portfolio_returns.columns,
show_index=True,
)
console.print("\n")
export_data(
export,
os.path.dirname(os.path.abspath(__file__)),
"mret_portfolio",
portfolio_returns,
sheet_name,
)
elif instrument == "benchmark":
print_rich_table(
benchmark_returns,
title="Monthly returns - benchmark [%]",
@@ -518,7 +530,49 @@ def display_monthly_returns(
show_index=True,
)
else:
export_data(
export,
os.path.dirname(os.path.abspath(__file__)),
"mret_benchmark",
benchmark_returns,
sheet_name,
)
elif instrument == "both":
# Converts multi-index into readable rich table while keeping the multi-index intact for export
total_monthly_returns_rich = total_monthly_returns.copy()
total_monthly_returns_rich.insert(
0, "Instruments", total_monthly_returns_rich.index.get_level_values(1)
)
total_monthly_returns_rich.insert(
0,
"Year",
sum(
[
[year, "", ""]
for year in total_monthly_returns_rich.index.get_level_values(
0
).unique()
],
[],
),
)
print_rich_table(
total_monthly_returns_rich,
title="Total Monthly returns [%]",
headers=total_monthly_returns_rich.columns,
show_index=False,
)
export_data(
export,
os.path.dirname(os.path.abspath(__file__)),
"mret_total",
total_monthly_returns,
sheet_name,
)
if graph or show_vals:
if external_axes is None:
_, ax = plt.subplots(
2,
@@ -564,14 +618,6 @@ def display_monthly_returns(
if external_axes is None:
theme.visualize_output()
export_data(
export,
os.path.dirname(os.path.abspath(__file__)),
"mret",
portfolio_returns,
sheet_name,
)
@log_start_end(log=logger)
def display_daily_returns(