This Python-based portfolio roboadvisor is designed to optimize a portfolio for risk-averse investors. It takes a CSV file containing a random list of stock tickers, processes the data, and generates a portfolio that balances risk and return using Monte Carlo simulations. For more details, feel free to explore the Jupyter Notebook.
This project was part of the CFM101 course offered by the University of Waterloo, and was entered into a portfolio generation competition and tested against live stock data, and ranked third among 20 competing groups. The generated portfolio can be found here on Yahoo Finance, which has achieved a 20% return YTD, as of September 2024.
- Python (pandas, NumPy, Matplotlib)
- Yahoo Finance API
- Jupyter Notebook
1. Data Preprocessing
- Filtered out delisted, non-existent, and low-volume stock tickers
- Fetched historical stock data using the Yahoo Finance API
- Implemented ETL batch processing by separating Canadian-listed and US-listed stocks, improving data retrieval effiency
- Converted US stock prices to Canadian dollars (CAD) to standardize data
2. Financial Analysis
- Calculated statistical measures using pandas to identify stocks with optimal risk and return (ex. standard deviation, beta, correlation, etc)
- Generated sets of potential portfolio candidates based on statistical and graphical analysis
3. Portfolio Optimization
- Conducted Monte Carlo simulations to generate random weighting variations for portfolio candidates
- Visualized 10,000 portfolio performances on a normalized risk-return plane
- Identified final portfolio with the best risk-return tradeoff
Given a random list of stock tickers, the portfolio roboadvisor generates a portfolio with select stocks and weights using 750,000 CAD that optimizes for risk and return. An example is shown below, which uses the random_tickers.csv
file:
Ticker | Price | Currency | Shares | Value | Weight | |
---|---|---|---|---|---|---|
1 | RY.TO | 118.959999 | CAD | 1171.745860 | 139390.886413 | 0.185861 |
2 | T.TO | 24.059999 | CAD | 2408.955568 | 57959.469683 | 0.077286 |
3 | TD.TO | 83.349998 | CAD | 1495.364161 | 124638.600532 | 0.166191 |
4 | KO | 80.211615 | USD | 212.504861 | 17045.358176 | 0.022734 |
5 | PEP | 231.952210 | USD | 73.465596 | 17040.507405 | 0.022727 |
6 | CL | 105.876042 | USD | 167.983406 | 17785.418206 | 0.023720 |
7 | PG | 207.314918 | USD | 84.876343 | 17596.132203 | 0.023468 |
8 | BMY | 68.146318 | USD | 250.069619 | 17041.323858 | 0.022728 |
9 | MRK | 139.510970 | USD | 840.021872 | 117192.266055 | 0.156263 |
10 | PM | 129.198626 | USD | 131.895760 | 17040.750973 | 0.022728 |
11 | ABBV | 189.908564 | USD | 95.048040 | 18050.436834 | 0.024074 |
12 | LMT | 619.027713 | USD | 27.528353 | 17040.813296 | 0.022728 |
13 | MO | 56.793167 | USD | 300.190751 | 17048.783489 | 0.022738 |
14 | ABT | 140.880470 | USD | 123.428161 | 17388.617273 | 0.023191 |
15 | UNH | 749.253422 | USD | 22.795996 | 17079.977869 | 0.022780 |
16 | PFE | 41.769750 | USD | 407.962823 | 17040.505251 | 0.022727 |
17 | UNP | 307.151461 | USD | 55.816962 | 17144.261311 | 0.022866 |
18 | UPS | 208.205085 | USD | 85.818505 | 17867.849137 | 0.023830 |
19 | BK | 64.845823 | USD | 264.429332 | 17147.137784 | 0.022869 |
20 | ACN | 457.467795 | USD | 37.249720 | 17040.547166 | 0.022727 |
21 | TXN | 210.341502 | USD | 81.036586 | 17045.357171 | 0.022734 |
22 | BAC | 40.715235 | USD | 424.069763 | 17266.099914 | 0.023028 |
- Pandas: Data cleaning, preprocessing, manipulation, and analysis.
- Matplotlib: Data visualization.
- yfinance: API for historical stock data.