1111
1212
1313def plot_portfolio (portfolio , title , tac , cash ):
14- """Main function to plot the portfolio performance and metrics."""
14+ """Plots the portfolio performance and associated financial metrics.
15+
16+ Args:
17+ portfolio (pd.DataFrame): A DataFrame containing the portfolio's assets, shares,
18+ and prices.
19+ title (str): Title of the plot.
20+ tac (float): Transaction costs.
21+ cash (float): Initial cash.
22+
23+ Returns:
24+ (go.Figure) Figure with portfolio performance and metrics.
25+ """
26+ # Note that there is no need to validate the inputs 'portfolio', 'tac' and 'cash',
27+ # since they are already checked in 'download_data.py' and 'backtest_signals.py".
1528 portfolio_return = _calculate_portfolio_return (portfolio ["assets" ])
1629 annualized_return = _calculate_annualized_return (portfolio ["assets" ])
1730 annualized_volatility = _calculate_annualized_volatility (portfolio ["assets" ])
31+ trades = _calculate_trades (portfolio ["shares" ])
1832
19- # Benchmark: Buy and Hold Strategy
2033 portfolio ["buy_and_hold" ] = _buy_and_hold_strategy (cash , portfolio ["Close" ])
2134 buy_and_hold_return = _calculate_annualized_return (portfolio ["buy_and_hold" ])
2235 buy_and_hold_volatility = _calculate_annualized_volatility (
2336 portfolio ["buy_and_hold" ]
2437 )
2538
26- trades = _calculate_trades (portfolio ["shares" ])
2739 fig = make_subplots (
2840 rows = 2 ,
2941 cols = 1 ,
@@ -33,7 +45,10 @@ def plot_portfolio(portfolio, title, tac, cash):
3345 specs = [[{"type" : "xy" }], [{"type" : "domain" }]],
3446 )
3547
36- for trace in _create_portfolio_traces (portfolio ):
48+ portfolio_traces = _create_portfolio_traces (
49+ portfolio .index , portfolio ["cash" ], portfolio ["assets" ]
50+ )
51+ for trace in portfolio_traces :
3752 fig .add_trace (trace , row = 1 , col = 1 )
3853
3954 metrics_table = _create_metrics_table (
@@ -52,13 +67,13 @@ def plot_portfolio(portfolio, title, tac, cash):
5267 return fig
5368
5469
55- def _create_portfolio_traces (portfolio ):
70+ def _create_portfolio_traces (index , cash , assets ):
5671 """Create Plotly traces for cash and assets over time."""
5772 traces = [
58- go .Scatter (x = portfolio . index , y = portfolio [ " cash" ] , mode = "lines" , name = "Cash" ),
73+ go .Scatter (x = index , y = cash , mode = "lines" , name = "Cash" ),
5974 go .Scatter (
60- x = portfolio . index ,
61- y = portfolio [ " assets" ] ,
75+ x = index ,
76+ y = assets ,
6277 mode = "lines" ,
6378 name = "Assets (Cash + Holdings)" ,
6479 ),
@@ -160,6 +175,7 @@ def _calculate_trades(shares):
160175
161176
162177def _calculate_annualized_volatility (stock ):
178+ """Calculates the annualized volatility for a stock."""
163179 if len (stock ) <= 1 :
164180 return 0
165181
@@ -176,10 +192,13 @@ def _calculate_annualized_volatility(stock):
176192
177193
178194def _buy_and_hold_strategy (initial_cash , prices ):
195+ """Calculates the portfolio development using a buy and hold strategy."""
179196 first_price = prices .iloc [0 ]
180197
181198 if first_price == 0 :
182199 return 0
183200
184201 shares = np .floor (initial_cash / first_price )
185- return shares * prices
202+ not_invested_cash = initial_cash - shares * first_price
203+ portfolio_buy_and_hold = shares * prices + not_invested_cash
204+ return portfolio_buy_and_hold
0 commit comments