Untitled
unknown
plain_text
10 months ago
6.8 kB
8
Indexable
# -------------------------------
# 4. Performance Metrics Calculation
# -------------------------------
# Load the risk free rate data
risk_free_filepath = r"\\asiapac.nom\data\MUM\IWM\India_IWM_IPAS\Reet\Momentum Strategy\Codes\Risk Free Rate.xlsx"
risk_free_df = pd.read_excel(risk_free_filepath, sheet_name="Risk Free Rate", parse_dates=[0])
risk_free_df.columns = ['Date', '1m', '3m']
def calculate_sharpe_ratio(returns, period):
volatility = returns.std()
avg_return = returns.mean()
# Map rebalance period to an annualization factor
annualization_factor = {1: 12, 2: 6, 3: 4}.get(period, 12) # Default to 12 if not found
return (avg_return / volatility) * (annualization_factor ** 0.5) if volatility > 0 else np.nan
# Ensure that there is a 'Date' column (if not, reset the index)
if 'Date' not in result_df.columns:
result_df = result_df.reset_index().rename(columns={'index': 'Date'})
# Merge risk free rate data on the 'Date' column
merged_df = pd.merge(result_df, risk_free_df, on='Date', how='left')
if rebalance_period == 1:
merged_df['rf_adjust'] = merged_df['1m'] / 12
elif rebalance_period == 2:
merged_df['rf_adjust'] = merged_df['1m'] / 6
elif rebalance_period == 3:
merged_df['rf_adjust'] = merged_df['1m'] / 4
else:
merged_df['rf_adjust'] = 0
# Compute excess returns by subtracting the risk free rate from monthly returns
merged_df['Excess Return'] = merged_df['Return'] - (merged_df['rf_adjust']/100)
# Calculate performance metrics using excess returns
excess_returns = merged_df['Excess Return'].dropna()
sharpe_ratio = calculate_sharpe_ratio(excess_returns, rebalance_period)
annualization_factor = {1: 12, 2: 6, 3: 4}.get(rebalance_period, 12)
avg_monthly_excess_return = excess_returns.mean()
monthly_excess_volatility = excess_returns.std()
annualized_volatility = monthly_excess_volatility * (annualization_factor ** 0.5)
annualised_risk_premium = avg_monthly_excess_return * annualization_factor
# The rest of your existing calculations remain the same
initial_aum = result_df['Portfolio Value'].iloc[0]
final_aum = result_df['Portfolio Value'].iloc[-1]
cumulative_return = (final_aum / initial_aum) - 1
if isinstance(start_date, str):
start_date = datetime.strptime(start_date, '%Y-%m-%d')
if isinstance(end_date, str):
end_date = datetime.strptime(end_date, '%Y-%m-%d')
num_months = (end_date.year - start_date.year) * 12 + (end_date.month - start_date.month)
annualized_return = ((1 + cumulative_return) ** (12 / num_months)) - 1
def compute_max_drawdown(returns):
cumulative = (1 + returns).cumprod()
running_max = cumulative.cummax()
drawdown = (cumulative - running_max) / running_max
return drawdown.min()
max_drawdown = compute_max_drawdown(result_df['Return'])
# Calculate annual returns
annual_returns = result_df.groupby(result_df['Date'].dt.year)['Return'].apply(lambda x: (1 + x).prod() - 1)
min_annual_return = annual_returns.min()
max_annual_return = annual_returns.max()
# Create a DataFrame with all metrics
metrics_df = pd.DataFrame({
'Metric': [
'Cumulative Return',
'Annualized Return',
'Average Monthly Excess Return',
'Monthly Excess Volatility',
'Annualized Volatility',
'Sharpe Ratio',
'Annualized Risk Premium',
'Maximum Drawdown',
'Minimum Annual Return',
'Maximum Annual Return'
],
'Value': [
cumulative_return,
annualized_return,
avg_monthly_excess_return,
monthly_excess_volatility,
annualized_volatility,
sharpe_ratio,
annualised_risk_premium,
max_drawdown,
min_annual_return,
max_annual_return
]
})
# Format the values as percentages where appropriate
percentage_metrics = ['Cumulative Return', 'Annualized Return', 'Average Monthly Excess Return',
'Monthly Excess Volatility', 'Annualized Volatility', 'Maximum Drawdown',
'Minimum Annual Return', 'Maximum Annual Return', 'Annualized Risk Premium']
for metric in percentage_metrics:
metrics_df.loc[metrics_df['Metric'] == metric, 'Value'] = metrics_df.loc[metrics_df['Metric'] == metric, 'Value'].apply(lambda x: f"{x:.2%}")
# Format Sharpe Ratio to 2 decimal places
metrics_df.loc[metrics_df['Metric'] == 'Sharpe Ratio', 'Value'] = metrics_df.loc[metrics_df['Metric'] == 'Sharpe Ratio', 'Value'].apply(lambda x: f"{x:.2f}")
print("\nPerformance Metrics for the Portfolio:")
print(metrics_df.to_string(index=False))
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import pandas as pd
def plot_drawdown(result_df, months=None):
# Ensure we're working with a copy to avoid modifying the original DataFrame
df = result_df.copy()
# If 'Date' is not the index, set it as the index
if 'Date' in df.columns:
df.set_index('Date', inplace=True)
# Calculate drawdown
drawdown = calculate_drawdown(df)
# If months is specified, filter the data
if months:
end_date = df.index[0] + pd.DateOffset(months=months)
drawdown = drawdown[drawdown.index <= end_date]
plt.figure(figsize=(12, 6))
plt.plot(drawdown.index, drawdown, color='red', linewidth=1)
plt.fill_between(drawdown.index, drawdown, 0, color='red', alpha=0.3)
title = 'Portfolio Drawdown'
if months:
title += f' (First {months} Months)'
plt.title(title)
plt.xlabel('Date')
plt.ylabel('Drawdown')
plt.grid(True, linestyle='--', alpha=0.7)
# Format y-axis as percentage
plt.gca().yaxis.set_major_formatter(plt.FuncFormatter(lambda y, _: '{:.0%}'.format(y)))
# Format x-axis to show dates properly
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
plt.gca().xaxis.set_major_locator(mdates.AutoDateLocator())
# Rotate and align the tick labels so they look better
plt.gcf().autofmt_xdate()
# Remove spines
ax = plt.gca()
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)
plt.tight_layout()
plt.show()
# Assuming result_df is your simulation result DataFrame
# Plot for the entire period
plot_drawdown(result_df)
# Plot for the first 18 months
plot_drawdown(result_df, months=18)
colors = ['#CA2420', '#737373', '#80A9AE', '#00305C', '#80003F', '#CC8D19', '#AEADB0', '#00713B', '#DCB940', '#00677A', '#9A9500', '#8F3336', '#5A7400', '#B0CAD0', '#6077A3', '#995E7A', '#DCB172', '#D4D4D4', '#6B9977', '#E5CC89', '#649CB3', '#B7B56B', '#BF8B79', '#8F9D66', '#000000']
Editor is loading...
Leave a Comment