def plot_theoretical_efficient_frontier(returns, risk_free_rate=0.0, points=100):
"""
Vẽ đường biên hiệu quả lý thuyết
Tham số:
returns (pd.DataFrame): DataFrame chứa lợi nhuận
risk_free_rate (float): Lãi suất phi rủi ro (annualized)
points (int): Số điểm để vẽ đường biên hiệu quả
"""
plt.figure(figsize=(12, 8))
min_vol_weights, min_vol_return, min_vol_risk, _ = optimize_portfolio(returns, risk_free_rate, target_return=None)
max_sharpe_weights, max_sharpe_return, max_sharpe_risk, max_sharpe = optimize_portfolio(returns, risk_free_rate)
target_returns = np.linspace(min_vol_return, max(returns.mean()) * 252 * 1.2, points)
efficient_risk = []
efficient_return = []
for target in target_returns:
try:
weights, ret, risk, _ = optimize_portfolio(returns, risk_free_rate, target_return=target)
efficient_risk.append(risk)
efficient_return.append(ret)
except:
pass
plt.plot(efficient_risk, efficient_return, 'b-', linewidth=3, label='Đường biên hiệu quả')
plt.scatter(min_vol_risk, min_vol_return, marker='*', color='g', s=500,
label='Danh mục có độ biến động thấp nhất')
plt.scatter(max_sharpe_risk, max_sharpe_return, marker='*', color='r', s=500,
label='Danh mục tối ưu theo Sharpe')
x_cml = np.linspace(0, max(efficient_risk) * 1.2, 100)
y_cml = risk_free_rate + x_cml * (max_sharpe_return - risk_free_rate) / max_sharpe_risk
plt.plot(x_cml, y_cml, 'r--', label='CML')
for i, ticker in enumerate(returns.columns):
individual_return = returns.mean()[i] * 252
individual_volatility = returns.std()[i] * np.sqrt(252)
plt.scatter(individual_volatility, individual_return, marker='o', s=200,
color='black')
plt.annotate(ticker, (individual_volatility, individual_return),
xytext=(10, 5), textcoords='offset points')
plt.title('Đường biên hiệu quả lý thuyết', fontsize=16)
plt.xlabel('Độ biến động (Rủi ro)', fontsize=14)
plt.ylabel('Lợi nhuận kỳ vọng', fontsize=14)
plt.legend()
print("Danh mục tối ưu theo tỷ lệ Sharpe:")
print(f"Lợi nhuận kỳ vọng: {max_sharpe_return:.4f}")
print(f"Độ biến động: {max_sharpe_risk:.4f}")
print(f"Tỷ lệ Sharpe: {max_sharpe:.4f}")
print("\nPhân bổ vốn:")
for i, ticker in enumerate(returns.columns):
print(f"{ticker}: {max_sharpe_weights[i] * 100:.2f}%")
plt.tight_layout()