Mathew K Analytics

Lesson 20 · Real-World Data Analytics

Python Data Analytics #20: Finance Capstone — Real Multi-Asset Portfolio Report

Video twenty of the hundred-video real-world data analytics series, and the capstone of the Finance and Stock Market domain. Recomputing every headline…

📓 Full notebook

Download .ipynb

Data Analytics 100, Video 20: Capstone, Building a Real Multi-Asset Portfolio Report#

  • Video twenty of the hundred-video real-world data analytics series, and the capstone of the Finance and Stock Market domain.
  • Recomputing every headline number fresh, from every real dataset used across this domain, into one consolidated real report.
  • Let's get into it.

Part 1: Nine Videos, One Real Report#

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
aapl = pd.read_csv('aapl_clean.csv', parse_dates=['Date'])
tsla = pd.read_csv('tsla_clean.csv', parse_dates=['date'])

Part 2: Real Data Foundation Recap#

merged = pd.read_csv('aapl_tsla_merged.csv', parse_dates=['Date'])
multi_stock = pd.read_csv('multi_stock_2007.csv', parse_dates=['Date'])
eth = pd.read_csv('eth_price_onchain.csv', parse_dates=['Date'])
fundamentals = pd.read_csv('sp500_fundamentals.csv')
len(aapl), len(tsla), len(merged), len(multi_stock), len(eth), len(fundamentals)
(506, 756, 338, 1098, 158, 337)

Part 3: Real Apple and Real Tesla, Fresh Volatility#

aapl_return = aapl['AAPL.Close'].pct_change().dropna()
tsla_return = tsla['close'].pct_change().dropna()
aapl_vol = round(aapl_return.std() * np.sqrt(252) * 100, 1)
tsla_vol = round(tsla_return.std() * np.sqrt(252) * 100, 1)
aapl_vol, tsla_vol
(np.float64(24.3), np.float64(44.0))

Part 4: Real Minimum-Variance Portfolio, Fresh#

weights_grid = np.linspace(0, 1, 41)
cov_matrix = merged[['AAPL_Return', 'TSLA_Return']].dropna().cov() * 252
portfolio_vols = [np.sqrt(w**2 * cov_matrix.iloc[0,0] + (1-w)**2 * cov_matrix.iloc[1,1] + 2*w*(1-w)*cov_matrix.iloc[0,1]) for w in weights_grid]
min_var_weight = weights_grid[np.argmin(portfolio_vols)]
round(min_var_weight, 2), round(min(portfolio_vols) * 100, 1)
(np.float64(0.8), np.float64(21.8))

Part 5: Real Diversification Benefit, Multi-Asset Set#

wide_multi = multi_stock.pivot(index='Date', columns='stock', values='value').sort_index().dropna()
multi_returns = wide_multi.pct_change().dropna()
stock_cols = ['AAPL', 'MSFT', 'IBM', 'SBUX']
equal_weight_vol = round(multi_returns[stock_cols].mean(axis=1).std() * np.sqrt(252) * 100, 1)
avg_individual_vol = round(multi_returns[stock_cols].std().mean() * np.sqrt(252) * 100, 1)
equal_weight_vol, avg_individual_vol
(np.float64(19.6), np.float64(25.9))

Part 6: Real Technical Signal Snapshot#

close = aapl['AAPL.Close']
sma20 = close.rolling(20).mean()
sma50 = close.rolling(50).mean()
latest_signal = 'Bullish (SMA20 above SMA50)' if sma20.iloc[-1] > sma50.iloc[-1] else 'Bearish (SMA20 below SMA50)'
latest_signal
'Bullish (SMA20 above SMA50)'

Part 7: Real Backtest Result, Recomputed#

position = (sma20 > sma50).astype(int).shift(1).fillna(0)
trade_flags = position.diff().abs().fillna(0)
net_strategy_return = position * aapl['AAPL.Close'].pct_change() - trade_flags * 0.001
strategy_growth = round((1 + net_strategy_return.fillna(0)).cumprod().iloc[-1], 3)
buyhold_growth = round((1 + aapl['AAPL.Close'].pct_change().fillna(0)).cumprod().iloc[-1], 3)
strategy_growth, buyhold_growth
(np.float64(1.053), np.float64(1.059))

Part 8: Real Crypto Volatility, Recomputed#

eth_return = eth['PriceUSD'].pct_change().dropna()
eth_vol = round(eth_return.std() * np.sqrt(365) * 100, 1)
eth_vol
np.float64(190.8)

Part 9: Real Fundamentals Screen, Recomputed#

clean_funds = fundamentals.dropna(subset=['Price/Earnings', 'Price/Book'])
value_screen = clean_funds[(clean_funds['Price/Earnings'] < 15) & (clean_funds['Price/Earnings'] > 0) & (clean_funds['Price/Book'] < 3)]
len(value_screen)
45

Part 10: Real VaR and Real Max Drawdown, Recomputed#

aapl_var95 = round(np.percentile(aapl_return, 5) * 100, 2)
cumulative_aapl = (1 + aapl_return).cumprod()
aapl_max_dd = round(((cumulative_aapl - cumulative_aapl.cummax()) / cumulative_aapl.cummax()).min() * 100, 1)
aapl_var95, aapl_max_dd
(np.float64(-2.49), np.float64(-32.1))

Part 11: Building the Real Consolidated Dashboard#

fig, axes = plt.subplots(2, 2, figsize=(13, 10))
axes[0, 0].bar(['Apple', 'Tesla', 'Ethereum'], [aapl_vol, tsla_vol, eth_vol], color=['steelblue', 'crimson', 'darkorange'])
axes[0, 0].set_title('Real Annualized Volatility (%)')
axes[0, 1].plot(aapl['Date'].iloc[1:], cumulative_aapl, color='steelblue')
axes[0, 1].set_title('Real Apple Cumulative Growth')
axes[1, 0].bar(['Equal-Weight' + chr(10) + 'Portfolio', 'Avg Individual' + chr(10) + 'Stock'], [equal_weight_vol, avg_individual_vol], color=['seagreen', 'gray'])
axes[1, 0].set_title('Real Diversification Benefit (%)')
axes[1, 1].bar(['SMA Crossover' + chr(10) + '(Net)', 'Buy and Hold'], [strategy_growth, buyhold_growth], color=['purple', 'gray'])
axes[1, 1].set_title('Real Growth of $1, Strategy vs Buy-Hold')
plt.tight_layout()
plt.savefig('capstone_finance_dashboard.png', dpi=120)
plt.close()

Part 12: Real Metrics Table#

metrics_table = pd.DataFrame({'Metric': ['Apple Annualized Vol (%)', 'Tesla Annualized Vol (%)', 'Ethereum Annualized Vol (%)', 'Min-Variance Apple Weight', 'Equal-Weight Portfolio Vol (%)', 'SMA Crossover Net Growth ($1 to)', 'Buy-and-Hold Growth ($1 to)', 'Apple VaR 95% (%)', 'Apple Max Drawdown (%)', 'Value Screen Company Count'], 'Value': [aapl_vol, tsla_vol, eth_vol, round(min_var_weight, 2), equal_weight_vol, strategy_growth, buyhold_growth, aapl_var95, aapl_max_dd, len(value_screen)]})
metrics_table.to_csv('capstone_finance_metrics.csv', index=False)
metrics_table
Metric Value
0 Apple Annualized Vol (%) 24.300
1 Tesla Annualized Vol (%) 44.000
2 Ethereum Annualized Vol (%) 190.800
3 Min-Variance Apple Weight 0.800
4 Equal-Weight Portfolio Vol (%) 19.600
5 SMA Crossover Net Growth ($1 to) 1.053
6 Buy-and-Hold Growth ($1 to) 1.059
7 Apple VaR 95% (%) -2.490
8 Apple Max Drawdown (%) -32.100
9 Value Screen Company Count 45.000

Part 13: Real Written Executive Summary#

summary_lines = []
summary_lines.append(f'FINANCE AND STOCK MARKET ANALYTICS - CAPSTONE SUMMARY')
summary_lines.append(f'Apple annualized volatility: {aapl_vol}% | Tesla: {tsla_vol}% | Ethereum: {eth_vol}%')
summary_lines.append(f'Minimum-variance Apple/Tesla portfolio: {round(min_var_weight*100)}% Apple, {round((1-min_var_weight)*100)}% Tesla')
summary_lines.append(f'Four-stock diversification cut volatility from {avg_individual_vol}% average to {equal_weight_vol}% combined')
summary_lines.append(f'SMA crossover strategy grew $1 to ${strategy_growth}, versus ${buyhold_growth} for buy-and-hold')
summary_lines.append(f'Apple one-day VaR at 95% confidence: {aapl_var95}%, maximum drawdown: {aapl_max_dd}%')
summary_lines.append(f'{len(value_screen)} S&P 500 companies passed a simple real value screen (P/E under 15, P/B under 3)')
len(summary_lines)
7

Part 14: Saving the Real Executive Summary#

with open('capstone_finance_summary.txt', 'w') as f:
    f.write(chr(10).join(summary_lines))
with open('capstone_finance_summary.txt') as f:
    saved_summary = f.read()
len(saved_summary) > 0
True

Part 15: Real Sanity Check, All Metrics Present#

metrics_table['Value'].notna().all()
np.True_

Part 16: Real Asset Class Volatility Ranking#

vol_ranking = pd.Series({'Apple': aapl_vol, 'Tesla': tsla_vol, 'Ethereum': eth_vol}).sort_values(ascending=False)
vol_ranking
Ethereum    190.8
Tesla        44.0
Apple        24.3
dtype: float64

Part 17: Real Domain Recap, Ten Lessons#

domain_lessons = ['Acquiring Real Stock Data', 'Portfolio Efficient Frontier', 'Technical Indicators', 'Volatility and Rolling Risk', 'Correlation and Diversification', 'Backtesting a Strategy', 'Cryptocurrency Analysis', 'Company Fundamentals', 'VaR and Drawdown', 'This Capstone']
len(domain_lessons)
10

Part 18: Real Total Real Datasets Used#

datasets_used = ['Apple daily prices', 'Tesla daily prices', 'Five-asset 2007 basket', 'Ethereum price and on-chain data', 'S&P 500 fundamentals snapshot']
len(datasets_used)
5

Part 19: Real Reload Verification#

reloaded_metrics = pd.read_csv('capstone_finance_metrics.csv')
reloaded_metrics.shape[0] == len(metrics_table)
True

Part 20: Real Final Recap Print#

print(f'Capstone complete: {len(datasets_used)} real datasets, {len(domain_lessons)} lessons, spanning {round(eth_vol/aapl_vol,1)}x more volatility in crypto than in Apple stock alone.')
Capstone complete: 5 real datasets, 10 lessons, spanning 7.9x more volatility in crypto than in Apple stock alone.

Part 21: Real Tesla Risk Metrics, Recomputed#

tsla_var95 = round(np.percentile(tsla_return, 5) * 100, 2)
cumulative_tsla = (1 + tsla_return).cumprod()
tsla_max_dd = round(((cumulative_tsla - cumulative_tsla.cummax()) / cumulative_tsla.cummax()).min() * 100, 1)
tsla_var95, tsla_max_dd
(np.float64(-4.1), np.float64(-40.1))

Part 22: Real Correlation Matrix, Recomputed#

fresh_corr = multi_returns.corr()
gspc_beta_msft = round(multi_returns['MSFT'].cov(multi_returns['GSPC']) / multi_returns['GSPC'].var(), 3)
gspc_beta_msft
np.float64(0.951)

Part 23: Real Negative Earnings Count, Recomputed#

eps_clean = fundamentals.dropna(subset=['Earnings/Share'])
negative_eps_count = (eps_clean['Earnings/Share'] < 0).sum()
negative_eps_count
np.int64(24)

Part 24: Real Ethereum Max Drawdown, Recomputed#

cumulative_eth = (1 + eth_return).cumprod()
eth_max_dd = round(((cumulative_eth - cumulative_eth.cummax()) / cumulative_eth.cummax()).min() * 100, 1)
eth_max_dd
np.float64(-77.7)

Part 25: Real Cross-Asset Drawdown Comparison#

drawdown_comparison = pd.Series({'Apple': aapl_max_dd, 'Tesla': tsla_max_dd, 'Ethereum': eth_max_dd}).sort_values()
drawdown_comparison
Ethereum   -77.7
Tesla      -40.1
Apple      -32.1
dtype: float64

Part 26: Real Best Single Day Across All Assets#

best_days = pd.Series({'Apple': round(aapl_return.max() * 100, 1), 'Tesla': round(tsla_return.max() * 100, 1), 'Ethereum': round(eth_return.max() * 100, 1)})
best_days.sort_values(ascending=False)
Ethereum    46.3
Tesla       17.3
Apple        6.5
dtype: float64

Part 27: Real Worst Single Day Across All Assets#

worst_days = pd.Series({'Apple': round(aapl_return.min() * 100, 1), 'Tesla': round(tsla_return.min() * 100, 1), 'Ethereum': round(eth_return.min() * 100, 1)})
worst_days.sort_values()
Ethereum   -23.7
Tesla      -13.9
Apple       -6.6
dtype: float64

Part 28: Real Dividend-Paying Share, Recomputed#

pct_paying_dividends = round(fundamentals['Dividend Yield'].notna().mean() * 100, 1)
pct_paying_dividends
np.float64(77.7)

Part 29: Real Total Real Trading Days Analyzed#

total_days_analyzed = len(aapl) + len(tsla) + len(multi_stock) // 5 + len(eth)
total_days_analyzed
1639

Part 30: Real Companies Analyzed Count#

total_companies_analyzed = len(fundamentals)
total_companies_analyzed
337

Wrap-Up: What You Learned#

  • A real capstone earns its name by recomputing headline numbers fresh from source data, not by copying cached results from earlier videos.
  • Stocks, crypto, and company fundamentals are three genuinely different real data shapes, time series, a second time series with far higher volatility, and a real cross-sectional snapshot.
  • Diversification, honest backtesting, and disciplined risk measurement are the real same three ideas that showed up again and again across this entire finance domain.
  • Volatility ranged from around twenty percent for Apple to well over one hundred fifty percent for early Ethereum, a real reminder that risk itself varies by orders of magnitude across asset classes.
  • This real ten-lesson domain used five independently sourced real datasets and zero synthetic data anywhere, real numbers from a real UCI-adjacent retail set all the way through crypto on-chain metrics.
  • Next domain: Marketing and Social Media Analytics, real text data, real engagement metrics, and a genuinely different set of real analytical tools.

Found this useful?

All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.