Personal portfolio performance analysis toolkit with statistical metrics, S&P 500 benchmark comparison, and automated monthly reporting.
Built using Python statistical libraries and Claude Agent SDK for advanced analysis.
Analyzes your brokerage portfolio (M1 Finance, Fidelity, Schwab, etc.) and provides:
- Performance vs S&P 500 - See if you're beating the market
- Statistical Metrics - Sharpe ratio, volatility, maximum drawdown
- Win Rate Analysis - Percentage of profitable days, average win/loss
- Visual Reports - Charts showing returns, drawdowns, and distributions
- Monthly Tracking - Automated workflow for regular portfolio reviews
Perfect for: Active investors who want to track portfolio performance with detailed metrics beyond what broker dashboards provide.
# Install Python packages
pip install pandas numpy matplotlib seaborn yfinance
# Install Claude Agent SDK (for advanced analysis - optional)
pip install claude-agent-sdk
# Install python-dotenv for environment variables
pip install python-dotenvOnly needed if using AI-powered advanced analysis:
Create a .env file:
ANTHROPIC_API_KEY='your-api-key-here'Get your API key from: https://console.anthropic.com/
From M1 Finance (or your broker):
- Export your holdings as CSV
- Save as:
data/my_broker_export.csv
Typical format:
Symbol,Name,Quantity,Price,Value
AAPL,Apple Inc,100,185.00,18500.00
VTI,Vanguard Total Stock,500,220.00,110000.00See data/sample_m1_export.csv for an example.
./monthly_review.shThat's it! Review the generated reports and charts.
| File | Purpose | When to Use |
|---|---|---|
monthly_review.sh |
Automated monthly analysis | Every month after exporting data |
convert_holdings_to_aggregate.py |
Converts broker CSV + fetches S&P 500 benchmark | Called by monthly_review.sh |
portfolio_analysis.py |
Detailed statistical analysis | Called by monthly_review.sh |
| File | Purpose | When to Use |
|---|---|---|
analyze_weighted_portfolio.py |
Position-level weighted analysis | When analyzing concentration risk |
analyze_volatility_context.py |
Multi-year volatility comparison | During volatile markets |
| File | Purpose |
|---|---|
create_weighted_portfolio_data.py |
Generate sample portfolio data |
create_sample_data.py |
Generate simple sample data |
data/sample_m1_export.csv |
Example M1 Finance export format |
Performance Metrics:
- Total return & annualized return
- Return vs S&P 500 benchmark
- Sharpe ratio (risk-adjusted returns)
- Maximum drawdown & recovery time
Trading Statistics:
- Win rate (% of profitable days)
- Average win vs average loss
- Maximum consecutive wins/losses
- Best & worst days
Monthly Analysis:
- Monthly returns breakdown
- Best & worst months
- Monthly volatility
cumulative_returns.png
Line chart showing your portfolio vs S&P 500 over time
monthly_returns.png
Bar chart of monthly performance (green = gains, red = losses)
drawdown_chart.png
Shows peak-to-trough declines (how much you lost from highs)
returns_distribution.png
Histogram and box plot of daily returns distribution
Step 1: Export from Your Broker
- Download current holdings as CSV
- Save as
data/my_broker_export.csv
Step 2: Run Analysis
./monthly_review.shStep 3: Review Results
# Read the report
cat portfolio_analysis.md | less
# View charts
open cumulative_returns.png
open monthly_returns.png
open drawdown_chart.png
open returns_distribution.pngStep 4: Track Over Time (Optional)
# Archive monthly snapshots
mkdir -p archive/2026-01
cp portfolio_analysis.md archive/2026-01/
cp cumulative_returns.png archive/2026-01/What: Risk-adjusted returns (return per unit of volatility) Good: > 1.0 (excellent: > 2.0) Meaning: Higher = better returns for the risk taken
What: Standard deviation of returns Γ β252 Typical: S&P 500 = 15-20% Meaning: Higher = larger price swings
What: Largest peak-to-trough decline Typical: S&P 500 = 10-20% in normal years Meaning: "Worst case" loss from a high point
What: % of days with positive returns Typical: 50-55% for most portfolios Meaning: Higher = more consistent gains
What: Your return minus S&P 500 return Good: Positive (you beat the market) Meaning: Shows if your stock picking adds value
Edit convert_holdings_to_aggregate.py to change the date range for S&P 500 benchmark:
# Fetch last 2 years instead of 1
start_date = daily_totals['date'].min() - timedelta(days=365)Edit convert_holdings_to_aggregate.py to compare against:
QQQ- Nasdaq 100 (tech heavy)VTI- Total US stock marketAGG- Total bond market- Any ticker symbol
# Change from SPY to QQQ
spy = yf.download('QQQ', start=start_date, end=end_date, progress=False)For more advanced analysis using Claude Agent SDK:
# Volatility context (is volatility normal or portfolio-specific?)
python analyze_volatility_context.py
# Position-level analysis (which holdings drive performance?)
python analyze_weighted_portfolio.py- Run monthly to track performance trends
- Look for allocation drift (positions getting too large)
- Monitor volatility - is it increasing?
- Beating S&P 500? You're adding value
- Underperforming? Consider index funds
- Higher volatility than S&P? You're taking more risk
- Max drawdown > 25%? You might be too aggressive
- Volatility > 25%? Portfolio may be too concentrated
- Win rate < 45%? Review your strategy
- Red flag: Single position > 15% of portfolio
- Red flag: Volatility 50%+ higher than S&P 500
- Red flag: Drawdown recovery time > 6 months
- Green flag: Outperformance with similar/lower volatility
Scenario: You want to know if your portfolio is beating the market.
# Export holdings from M1 Finance β save as data/my_broker_export.csv
./monthly_review.sh
# Review cumulative returns chart
open cumulative_returns.png
# β See if your line (blue) is above S&P 500 (red dashed)
# Check the report for exact numbers
cat portfolio_analysis.md | grep "Outperformance"
# β Example: "Outperformance: +15.23%" means you beat S&P by 15%
# Check if you're taking more risk for those returns
cat portfolio_analysis.md | grep "Volatility"
# β Your volatility: 25% vs S&P: 19%
# β You're more volatile, but is the extra return worth it?
# Check Sharpe ratio
cat portfolio_analysis.md | grep "Sharpe"
# β Your Sharpe: 1.2 vs S&P: 0.9
# β Yes! Higher Sharpe = better risk-adjusted returnsConclusion: You're beating the market with better risk-adjusted returns. Keep doing what you're doing!
- Make sure you exported from your broker
- Save the file as exactly:
data/my_broker_export.csv - Check you're in the right directory
pip install yfinanceOnly needed for advanced AI analysis. Skip or install:
pip install claude-agent-sdkMac:
open cumulative_returns.pngWindows:
start cumulative_returns.pngLinux:
xdg-open cumulative_returns.png- Make sure dates in your export match (check
portfolio_analysis.mdfor date range) - S&P 500 data might be delayed by 1 day (normal)
Some files use the Claude Agent SDK for AI-powered analysis:
analyze_weighted_portfolio.py- AI analyzes concentration risk and position-level performanceanalyze_volatility_context.py- AI compares your volatility to market benchmarks and historical periods
These scripts use natural language prompts to ask Claude to:
- Read your portfolio data
- Fetch historical prices
- Calculate metrics
- Generate insights and recommendations
- Create visualizations
The core monthly review doesn't use AI - it's pure Python for fast, deterministic analysis.
Monthly Review (Recommended):
- Fast, deterministic statistical analysis
- Compare to S&P 500
- Track performance metrics
- Use: Every month for regular tracking
AI-Powered Analysis (Optional):
- Deeper insights and recommendations
- Context-aware analysis (volatility regimes, market conditions)
- Custom questions and explorations
- Use: Quarterly or when you need strategic insights
- Initial release
- Monthly automated review workflow
- Statistical analysis with S&P 500 benchmark
- Four key visualization charts
- Support for M1 Finance and standard broker CSV exports
- AI-powered advanced analysis tools (optional)
This is a personal toolkit, but feel free to:
- Fork and adapt for your own needs
- Add new metrics or visualizations
- Integrate with other data sources
- Submit pull requests for improvements
This toolkit is for informational and educational purposes only. It is not financial advice.
- Past performance does not guarantee future results
- Always do your own research before making investment decisions
- Consider consulting a financial advisor for personalized advice
- The creators assume no liability for investment decisions made using this tool
Regular monthly review:
./monthly_review.shView results:
cat portfolio_analysis.md | less
open cumulative_returns.pngAdvanced analysis (optional):
python analyze_volatility_context.py # Volatility deep dive
python analyze_weighted_portfolio.py # Position-level analysisTest with sample data:
python create_weighted_portfolio_data.py
python analyze_weighted_portfolio.pyBuilt with: Python, pandas, matplotlib, seaborn, yfinance, Claude Agent SDK (optional) Version: 1.0 Last Updated: January 2026