|
|
""" |
|
|
Advanced Portfolio Analyzer - Usage Examples |
|
|
|
|
|
Demonstrates factor-based portfolio analysis with HRP and clustering. |
|
|
""" |
|
|
|
|
|
import asyncio |
|
|
from src.core.portfolio.advanced_portfolio_analyzer import AdvancedPortfolioAnalyzer |
|
|
from src.core.portfolio.advanced_portfolio_analyzer.visualizer import PortfolioVisualizer |
|
|
|
|
|
|
|
|
async def example_1_basic_usage(): |
|
|
"""Example 1: Basic factor-based analysis.""" |
|
|
print("\n=== Example 1: Basic Factor-Based Analysis ===\n") |
|
|
|
|
|
|
|
|
tickers = ["AAPL", "MSFT", "NVDA", "GOOGL", "AMZN"] |
|
|
|
|
|
|
|
|
factors = { |
|
|
"AI": "BOTZ", |
|
|
"Cloud": "SKYY", |
|
|
"Tech": "QQQ", |
|
|
} |
|
|
|
|
|
|
|
|
analyzer = AdvancedPortfolioAnalyzer( |
|
|
tickers=tickers, |
|
|
factors=factors, |
|
|
lookback_days=504 |
|
|
) |
|
|
|
|
|
|
|
|
result = await analyzer.analyze_portfolio() |
|
|
|
|
|
|
|
|
print(analyzer.format_summary(result)) |
|
|
|
|
|
|
|
|
async def example_2_with_current_weights(): |
|
|
"""Example 2: Analyze existing portfolio and get recommendations.""" |
|
|
print("\n=== Example 2: Rebalancing Recommendations ===\n") |
|
|
|
|
|
tickers = ["AAPL", "MSFT", "NVDA", "GOOGL", "AMZN"] |
|
|
factors = { |
|
|
"AI": "BOTZ", |
|
|
"Cloud": "SKYY", |
|
|
} |
|
|
|
|
|
|
|
|
current_weights = { |
|
|
"AAPL": 0.15, |
|
|
"MSFT": 0.15, |
|
|
"NVDA": 0.50, |
|
|
"GOOGL": 0.10, |
|
|
"AMZN": 0.10, |
|
|
} |
|
|
|
|
|
analyzer = AdvancedPortfolioAnalyzer(tickers, factors) |
|
|
result = await analyzer.analyze_portfolio(current_weights=current_weights) |
|
|
|
|
|
|
|
|
print("Rebalancing Recommendations:") |
|
|
print("-" * 70) |
|
|
for rec in result.recommendations: |
|
|
if rec.action != "HOLD": |
|
|
symbol = "↑" if rec.action == "INCREASE" else "↓" |
|
|
print(f"{symbol} {rec.ticker}:") |
|
|
print(f" Current: {rec.current_weight:.1%}") |
|
|
print(f" Target: {rec.target_weight:.1%}") |
|
|
print(f" Reason: {rec.reason}") |
|
|
print() |
|
|
|
|
|
|
|
|
async def example_3_factor_exposure(): |
|
|
"""Example 3: Analyze factor exposures.""" |
|
|
print("\n=== Example 3: Factor Exposure Analysis ===\n") |
|
|
|
|
|
tickers = ["NVDA", "AMD", "ASML", "TSM"] |
|
|
factors = { |
|
|
"AI": "BOTZ", |
|
|
"Semiconductors": "SOXX", |
|
|
"Technology": "QQQ", |
|
|
} |
|
|
|
|
|
analyzer = AdvancedPortfolioAnalyzer(tickers, factors) |
|
|
result = await analyzer.analyze_portfolio() |
|
|
|
|
|
|
|
|
print("Individual Asset Factor Exposures:") |
|
|
print("-" * 70) |
|
|
for fe in result.factor_exposures: |
|
|
print(f"\n{fe.ticker}:") |
|
|
for factor, beta in fe.exposures.items(): |
|
|
print(f" {factor:15s} {beta:+.2f}") |
|
|
print(f" R²: {fe.r_squared:.2%}") |
|
|
|
|
|
print("\n" + "=" * 70) |
|
|
print("Portfolio-Level Factor Exposure:") |
|
|
print("-" * 70) |
|
|
for factor, exposure in result.factor_portfolio_exposure.items(): |
|
|
print(f" {factor:15s} {exposure:+.2f}") |
|
|
|
|
|
|
|
|
async def example_4_clustering(): |
|
|
"""Example 4: Correlation clustering.""" |
|
|
print("\n=== Example 4: Correlation Clustering ===\n") |
|
|
|
|
|
|
|
|
tickers = [ |
|
|
"AAPL", "MSFT", |
|
|
"JPM", "BAC", |
|
|
"JNJ", "PFE", |
|
|
"XOM", "CVX", |
|
|
] |
|
|
|
|
|
factors = {"Tech": "QQQ", "Finance": "XLF"} |
|
|
|
|
|
analyzer = AdvancedPortfolioAnalyzer(tickers, factors) |
|
|
result = await analyzer.analyze_portfolio(n_clusters=4) |
|
|
|
|
|
|
|
|
print("Identified Clusters:") |
|
|
print("-" * 70) |
|
|
for cluster_id, cluster_tickers in result.cluster_result.clusters.items(): |
|
|
print(f"\nCluster {cluster_id}: {', '.join(cluster_tickers)}") |
|
|
|
|
|
|
|
|
print("\n" + "=" * 70) |
|
|
print("Correlation Matrix:") |
|
|
print(result.cluster_result.correlation_matrix.round(2)) |
|
|
|
|
|
|
|
|
async def example_5_hrp_details(): |
|
|
"""Example 5: HRP allocation details.""" |
|
|
print("\n=== Example 5: HRP Allocation Details ===\n") |
|
|
|
|
|
tickers = ["AAPL", "MSFT", "NVDA", "GOOGL", "AMZN"] |
|
|
factors = {"AI": "BOTZ", "Cloud": "SKYY"} |
|
|
|
|
|
analyzer = AdvancedPortfolioAnalyzer(tickers, factors) |
|
|
result = await analyzer.analyze_portfolio() |
|
|
|
|
|
|
|
|
comparison = analyzer.hrp_allocator.compare_with_equal_weight( |
|
|
result.hrp_weights, |
|
|
result.covariance_matrix.values |
|
|
) |
|
|
|
|
|
print("HRP vs Equal Weight Comparison:") |
|
|
print("-" * 70) |
|
|
print(f"Equal Weight Volatility: {comparison['equal_weight_volatility']:.2%}") |
|
|
print(f"HRP Volatility: {comparison['hrp_volatility']:.2%}") |
|
|
print(f"Volatility Reduction: {comparison['volatility_reduction']:.1f}%") |
|
|
print(f"EW Diversification Ratio: {comparison['equal_weight_diversification_ratio']:.2f}") |
|
|
print(f"HRP Diversification Ratio:{comparison['hrp_diversification_ratio']:.2f}") |
|
|
|
|
|
print("\n" + "=" * 70) |
|
|
print("Risk Contributions (HRP):") |
|
|
print("-" * 70) |
|
|
for ticker, rc in sorted( |
|
|
result.hrp_weights.risk_contributions.items(), |
|
|
key=lambda x: x[1], |
|
|
reverse=True |
|
|
): |
|
|
print(f" {ticker:6s} {rc:6.1%}") |
|
|
|
|
|
|
|
|
async def example_6_visualization(): |
|
|
"""Example 6: Create visualizations.""" |
|
|
print("\n=== Example 6: Creating Visualizations ===\n") |
|
|
|
|
|
tickers = ["AAPL", "MSFT", "NVDA", "GOOGL", "AMZN"] |
|
|
factors = {"AI": "BOTZ", "Cloud": "SKYY"} |
|
|
|
|
|
analyzer = AdvancedPortfolioAnalyzer(tickers, factors) |
|
|
result = await analyzer.analyze_portfolio() |
|
|
|
|
|
|
|
|
visualizer = PortfolioVisualizer() |
|
|
|
|
|
|
|
|
print("Creating correlation heatmap...") |
|
|
visualizer.plot_correlation_heatmap( |
|
|
result.cluster_result, |
|
|
save_path="correlation_heatmap.png" |
|
|
) |
|
|
|
|
|
print("Creating dendrogram...") |
|
|
visualizer.plot_dendrogram( |
|
|
result.cluster_result, |
|
|
save_path="dendrogram.png" |
|
|
) |
|
|
|
|
|
print("Creating weight comparison...") |
|
|
visualizer.plot_weight_comparison( |
|
|
result, |
|
|
save_path="weight_comparison.png" |
|
|
) |
|
|
|
|
|
print("Creating risk contribution chart...") |
|
|
visualizer.plot_risk_contribution( |
|
|
result, |
|
|
save_path="risk_contribution.png" |
|
|
) |
|
|
|
|
|
print("Creating factor exposure heatmap...") |
|
|
visualizer.plot_factor_exposure( |
|
|
result, |
|
|
save_path="factor_exposure.png" |
|
|
) |
|
|
|
|
|
|
|
|
print("Creating comprehensive dashboard...") |
|
|
visualizer.create_dashboard( |
|
|
result, |
|
|
save_path="portfolio_dashboard.png" |
|
|
) |
|
|
|
|
|
print("\n✓ All visualizations saved!") |
|
|
print(" - correlation_heatmap.png") |
|
|
print(" - dendrogram.png") |
|
|
print(" - weight_comparison.png") |
|
|
print(" - risk_contribution.png") |
|
|
print(" - factor_exposure.png") |
|
|
print(" - portfolio_dashboard.png") |
|
|
|
|
|
|
|
|
async def example_7_custom_factors(): |
|
|
"""Example 7: Custom factor definitions.""" |
|
|
print("\n=== Example 7: Custom Thematic Factors ===\n") |
|
|
|
|
|
|
|
|
tickers = ["AAPL", "MSFT", "NVDA", "AMD", "INTC", "QCOM"] |
|
|
|
|
|
|
|
|
factors = { |
|
|
"AI": "BOTZ", |
|
|
"Semiconductors": "SOXX", |
|
|
"Cloud": "SKYY", |
|
|
"Cybersecurity": "HACK", |
|
|
} |
|
|
|
|
|
analyzer = AdvancedPortfolioAnalyzer(tickers, factors, lookback_days=252) |
|
|
result = await analyzer.analyze_portfolio() |
|
|
|
|
|
print("Portfolio Factor Exposure (Custom Themes):") |
|
|
print("-" * 70) |
|
|
for factor, exposure in result.factor_portfolio_exposure.items(): |
|
|
status = "✓ Strong" if abs(exposure) > 1.0 else "○ Moderate" |
|
|
print(f" {status} {factor:15s} {exposure:+.2f}") |
|
|
|
|
|
|
|
|
async def main(): |
|
|
"""Run all examples.""" |
|
|
examples = [ |
|
|
example_1_basic_usage, |
|
|
example_2_with_current_weights, |
|
|
example_3_factor_exposure, |
|
|
example_4_clustering, |
|
|
example_5_hrp_details, |
|
|
example_6_visualization, |
|
|
example_7_custom_factors, |
|
|
] |
|
|
|
|
|
for example in examples: |
|
|
try: |
|
|
await example() |
|
|
except Exception as e: |
|
|
print(f"\n✗ Example failed: {e}") |
|
|
import traceback |
|
|
traceback.print_exc() |
|
|
|
|
|
print("\n" + "=" * 70 + "\n") |
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
asyncio.run(main()) |
|
|
|