import numpy as np
import pandas as pd
[docs]
def generate_financial_metrics(random_returns_df, annual_risk_free=0.00):
"""
Calculate financial metrics based on a DataFrame of random returns on time series.
Parameters
----------
random_returns_df : pandas.DataFrame
DataFrame containing returns of stocks on time series in columns. Each column is an independent series of returns.
The supported frequencies of the index is 'D' for daily, 'H' for hourly and 'min' for minutely.
annual_risk_free : float, default 0.00.
Annualized risk-free rate as a decimal (e.g., 0.02 for 2%).
Returns
-------
pandas.DataFrame
A DataFrame containing financial metrics including count (number of returns),
total return, annualized return, annualized volatility, and Sharpe ratio for each
stock return series
Examples
--------
>>> random_returns_df = pd.DataFrame([
{'index': '2024-01-01 00:00:00', 'stock_1': -0.002286, 'stock_2': 0.002545, 'stock_3': 0.002997},
{'index': '2024-01-01 01:00:00', 'stock_1': 0.003045, 'stock_2': 0.002913, 'stock_3': -0.000855},
{'index': '2024-01-01 02:00:00', 'stock_1': -0.001142, 'stock_2': 0.000635, 'stock_3': -0.002592},
{'index': '2024-01-01 03:00:00', 'stock_1': 0.000971, 'stock_2': -0.000168, 'stock_3': 0.000074},
{'index': '2024-01-01 04:00:00', 'stock_1': -0.000392, 'stock_2': 0.002252, 'stock_3': -0.000342}
])
>>> generate_financial_metrics(random_returns_df, annual_risk_free=0.02)
count total_return annual_return annual_volatility sharpe_ratio
stock_1 5 0.000196 0.343184 0.192332 1.680339
stock_2 5 0.008177 14.325234 0.124650 114.763058
stock_3 5 -0.000718 -1.258381 0.189806 -6.735214
"""
if random_returns_df.empty:
raise ValueError("Random returns DataFrame is empty.")
if not isinstance(random_returns_df.index, pd.DatetimeIndex):
raise ValueError("Index must be a pd.DatetimeIndex.")
if random_returns_df.isnull().values.any():
raise ValueError("Random returns DataFrame contains missing values.")
if not isinstance(annual_risk_free, (int, float)):
raise ValueError("Annual risk-free rate must be numeric.")
freq = pd.infer_freq(random_returns_df.index)
if freq == 'D':
periods_per_year = 365
elif freq == 'H':
periods_per_year = 365 * 24
elif freq == 'T':
periods_per_year = 365 * 24 * 60
else:
raise ValueError("Invalid frequency. Frequency should be either 'D' for daily, 'H' for hourly, or 'min' for minutely.")
metrics_df = pd.DataFrame({
'count': random_returns_df.count(),
'total_return': random_returns_df.sum(),
'annual_return': random_returns_df.mean() * periods_per_year,
'annual_volatility': random_returns_df.std() * np.sqrt(periods_per_year),
})
metrics_df['sharpe_ratio'] = (metrics_df['annual_return'] - annual_risk_free) / metrics_df['annual_volatility']
return metrics_df