Created
April 28, 2025 03:44
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def calculate_portfolio_performance( | |
stock_data: pd.DataFrame, | |
tickers: List[str], | |
allocations: Dict[str, float], | |
risk_free_rate: float = 0.02, | |
target_return: float = 0.0, | |
annualization_factor: float = 252 | |
) -> Dict[str, float]: | |
""" | |
Calculate comprehensive portfolio performance metrics. | |
Args: | |
stock_data: DataFrame with price data for each ticker | |
tickers: List of stock tickers | |
allocations: Dictionary mapping tickers to their weight allocations | |
risk_free_rate: Risk-free rate (annualized) | |
target_return: Minimum acceptable return for Sortino ratio (default: 0) | |
annualization_factor: Number of trading days in a year | |
Returns: | |
Dictionary with portfolio performance metrics | |
""" | |
# Ensure allocations are provided for all tickers | |
weights_dict = {ticker: allocations.get(ticker, 0) for ticker in tickers} | |
# Convert weights to numpy array | |
weights_array = weights_to_array(tickers, weights_dict) | |
# Calculate expected returns and covariance matrix | |
mu, S = calculate_returns_and_covariance(stock_data) | |
# Calculate basic portfolio metrics (expected return, std dev, Sharpe) | |
basic_metrics = calculate_portfolio_metrics(weights_array, mu, S, risk_free_rate) | |
# Calculate Sortino ratio | |
sortino_ratio = calculate_sortino_ratio( | |
weights_array, | |
stock_data, | |
risk_free_rate, | |
target_return, | |
annualization_factor | |
) | |
# Calculate max drawdown | |
daily_returns = stock_data.pct_change().dropna() | |
portfolio_returns = pd.Series(0, index=daily_returns.index) | |
for ticker, weight in weights_dict.items(): | |
if ticker in daily_returns.columns: | |
portfolio_returns += daily_returns[ticker] * weight | |
# Calculate cumulative returns | |
cumulative_returns = (1 + portfolio_returns).cumprod() | |
max_drawdown = (cumulative_returns / cumulative_returns.cummax() - 1).min() | |
# Combine all metrics | |
return { | |
"expected_return": basic_metrics["expected_return"], | |
"standard_deviation": basic_metrics["standard_deviation"], | |
"sharpe_ratio": basic_metrics["sharpe_ratio"], | |
"sortino_ratio": sortino_ratio, | |
"max_drawdown": float(max_drawdown), | |
"risk_free_rate": basic_metrics["risk_free_rate"] | |
} | |
########################################################################################## | |
# Example usage | |
tickers = ["AAPL", "MSFT", "GOOG"] | |
allocations = {"AAPL": 0.4, "MSFT": 0.3, "GOOG": 0.3} | |
# Fetch data | |
stock_data, _, _ = fetch_stock_data(tickers, "2020-01-01", "2023-01-01") | |
# Calculate metrics | |
performance = calculate_portfolio_performance(stock_data, tickers, allocations, risk_free_rate=0.02) | |
print(f"Expected Return: {performance['expected_return']:.2%}") | |
print(f"Standard Deviation: {performance['standard_deviation']:.2%}") | |
print(f"Sharpe Ratio: {performance['sharpe_ratio']:.2f}") | |
print(f"Sortino Ratio: {performance['sortino_ratio']:.2f}") | |
print(f"Maximum Drawdown: {performance['max_drawdown']:.2%}") | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment