Com5fs112 3 — Module 3
Lecture Notes
- MODULE III: DATA VISUALIZATION IN PYTHON MODULE OVERVIEW & QUANTITATIVE VISUAL ANALYTICS In contemporary capital markets, financial institutions, investment banks, and econometric research desks, raw tabular numbers alone are insufficient to communicate complex portfolio dynamics, nonlinear risk exposures, and asset correlations. Quantitative decision-makers require high-performance numerical engines coupled with expressive statistical visualization libraries. Module III explores the core components of the Python Scientific & Visual Analytics Stack. Students master highperformance multi-dimensional array computation and vectorization using NumPy; procedural and object-oriented chart generation via Matplotlib (line charts for equity trends, bar charts for performance benchmarks, pie charts for capital allocation, and histograms for return distributions); tabular time-series data engineering and cleaning using Pandas (Series, DataFrames, indexing, slicing, missing data imputation, and rolling financial statistics); and publication-grade statistical graphics using Seaborn (kernel density estimations, distribution plots, categorical box plots, and multi-asset correlation heatmaps).
UNIT 1: NUMPY LIBRARY, ARRAYS & VECTORIZED LINEAR ALGEBRA NumPy (Numerical Python) is the foundational library for scientific and financial computing in Python.
Standard Python lists, while versatile and capable of storing heterogeneous data types, are computationally inefficient for high-frequency financial calculations due to pointer overhead, dynamic type checking, and noncontiguous memory storage. NumPy introduces the homogeneous N-dimensional array (ndarray), which stores data in contiguous blocks of memory and delegates heavy computations to highly optimized C and Fortran linear algebra routines (BLAS and LAPACK).
- Memory: Architecture: Python Lists vs NumPy Arrays COMPUTATIONAL EFFICIENCY & VECTORIZATION ARCHITECTURE NUMPY ENGINE
- PYTHON LIST: POINTER ARRAY → DYNAMIC TYPE CHECKING → SLOW INTERPRETED LOOPS
- NUMPY NDARRAY: CONTIGUOUS C MEMORY → STATIC C DTYPES → HARDWARE SIMD VECTORIZATION
- Contiguous Memory Allocation: All elements in an ndarray occupy adjacent memory addresses, maximizing CPU cache line hits and eliminating memory fragmentation.
- Homogeneous Typing: Every element shares the exact same numeric data type (e.g., float64 or int32), eliminating per-element runtime type overhead.
- Vectorization & SIMD: Mathematical operations are executed across entire data vectors simultaneously using Single Instruction, Multiple Data (SIMD) processor instructions, running up to 50 to 100 times faster than native Python for loops.
- GIL Bypass: NumPy core operations release Python's Global Interpreter Lock (GIL), allowing multi-core parallel processing across financial matrices.
- Array: Creation Functions in Financial Computing NumPy provides versatile factory functions for initializing numerical arrays across financial modeling applications: import numpy as np # 1. Direct Conversion from Python Lists (Historical Stock Prices) closing_prices = np.array([1420.50, 1435.00, 1410.25, 1450.80, 1442.10], dtype=np.float64) # 2. Constant Array Initializations zero_weights = np.zeros(shape=5) # Initializing empty portfolio weights [0., 0., 0., 0., 0.] unit_factors = np.ones(shape= (3, 3)) # 3x3 Unit Matrix for factor exposures cash_reserves = np.full(shape=4, fill_value=100000.0) # Allocating INR 1L across 4 sub-accounts # 3. Numerical Sequences for Yield Curve and Horizon Modeling tenures = np.arange(start=1, stop=11, step=1) # Loan tenures: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] interest_grid = np.linspace(start=0.05, stop=0.15, num=5) # 5 evenly spaced rates: [0.05, 0.075, 0.10, 0.125, 0.15] # 4.
Stochastic Asset Price Simulations (Normal Distribution) daily_random_shocks = np.random.normal(loc=0.0005, scale=0.015, size=252) # 252 trading days
- Key: Attributes of the ndarray Object ndarray.ndim: The number of array dimensions / axes (e.g., 1 for a single asset price series; 2 for a multiasset historical matrix). ndarray.shape: A tuple of integers indicating the size of the array along each dimension (e.g., (252, 5) represents 252 trading days across 5 securities). ndarray.size: Total number of elements across all axes (e.g., 252 × 5 = 1,260 values). ndarray.dtype: Data type of the array elements (e.g., np.float64, np.int32). ndarray.itemsize: Memory size of each element in bytes (e.g., 8 bytes for float64). ndarray.nbytes: Total memory consumed by array elements: size × itemsize.
- Array: Indexing, Slicing & Boolean Masking Accessing and subsetting financial arrays follows zero-based indexing and multidimensional slicing: # Multidimensional Matrix: 3 Assets across 4 Trading Days price_matrix = np.array([ [100.0, 102.0, 101.5, 103.0], # Stock A (Reliance) [50.0, 49.5, 51.0, 52.5], # Stock B (Tata Motors) [200.0, 198.0, 202.0, 205.0] # Stock C (Infosys) ]) # Slicing: [row_slice, col_slice] stock_a_all_days = price_matrix[0, :] # Extracts entire row 0: [100.0, 102.0, 101.5, 103.0] day_4_all_stocks = price_matrix[:, 3] # Extracts final trading day: [103.0, 52.5, 205.0] sub_matrix = price_matrix[0:2, 1:3] # Stocks A & B on Days 2 & 3 #
- Boolean Masking: Filtering Abnormal Outliers daily_returns = np.array([0.015, -0.022, 0.035, -0.045, 0.008, 0.029]) extreme_volatility_days = daily_returns[np.abs(daily_returns) > 0.025] print("Outlier Return Days (> 2.5%):", extreme_volatility_days) # [0.035, -0.045, 0.029]
- Vectorized: Linear Algebra & Modern Portfolio Theory (MPT) In Modern Portfolio Theory (MPT), calculating portfolio return and variance requires matrix operations:
- Portfolio Expected Return: Vector dot product of portfolio weights vector and asset expected returns vector.
- Portfolio Variance: Quadratic matrix multiplication: Transposed weights vector × Covariance Matrix × Weights vector. # Modern Portfolio Theory Matrix Computation in NumPy weights = np.array([0.40, 0.35, 0.25]) # 3 Assets expected_returns = np.array([0.15, 0.12, 0.09]) # 15%, 12%, 9% # Covariance Matrix (Sigma) cov_matrix = np.array([ [0.040, 0.015, 0.010], [0.015, 0.030, 0.008], [0.010, 0.008, 0.020] ]) # 1. Portfolio Return via Vector Dot Product (w . R) portfolio_return = np.dot(weights, expected_returns) # 2. Portfolio Variance via Matrix Multiplication (w.T @ Sigma @ w) portfolio_variance = weights.T @ cov_matrix @ weights portfolio_std_dev = np.sqrt(portfolio_variance) print(f"Portfolio Expected Annual Return: {portfolio_return:.2%}") print(f"Portfolio Annual Variance: {portfolio_variance:.6f}") print(f"Portfolio Annualized Volatility (Risk): {portfolio_std_dev:.2%}")
- Stochastic: Monte Carlo Asset Price Simulation Financial derivatives pricing and Value at Risk (VaR) modeling rely on simulating future price trajectories using Geometric Brownian Motion (GBM). NumPy's vectorized operations generate thousands of paths simultaneously: # Geometric Brownian Motion (GBM) Simulation using NumPy np.random.seed(101) spot_price = 100.0 # Current Stock Price (INR) drift = 0.10 # 10% Expected Annual Return (mu) volatility = 0.20 # 20% Annual Volatility (sigma) time_horizon = 1.0 # 1 Year Horizon num_steps = 252 # 252 Trading Days num_paths = 1000 # 1,000 Parallel Simulation Trajectories dt = time_horizon / num_steps # Vectorized random standard normal innovations: Shape (252, 1000) random_shocks = np.random.normal(0, 1, size=(num_steps, num_paths)) # Daily return exponents based on Ito's Lemma: (mu - 0.5 * sigma^2) * dt + sigma * sqrt(dt) * Z daily_drift = (drift - 0.5 * (volatility**2)) * dt daily_diffusion = volatility * np.sqrt(dt) * random_shocks daily_multipliers = np.exp(daily_drift + daily_diffusion) # Cumulative product calculates complete price paths across all 1,000 assets simultaneously price_paths = np.vstack([np.full(num_paths, spot_price), spot_price * np.cumprod(daily_multipliers, axis=0)]) final_prices = price_paths[-1, :] expected_final_price = np.mean(final_prices) var_95 = spot_price np.percentile(final_prices, 5) print(f"Simulated Expected Price after 1 Year: INR {expected_final_price:,.2f}") print(f"95% Confidence 1-Year Value at Risk (VaR): INR {var_95:,.2f}")
- Linear: Algebra Solvers & Yield Curve Interpolation In fixed-income analytics, government zero-coupon bond discount factors are derived from swap yields by solving linear matrix equations via np.linalg.solve(), while term structure discount curves are fitted via np.interp(): # Fitting Term Structure of Interest Rates using np.interp() known_maturities = np.array([1, 2, 5, 10]) # Benchmark bond tenures (Years) known_yields = np.array([0.065, 0.068, 0.072, 0.076]) # Yields: 6.5%, 6.8%, 7.2%, 7.6% # Target tenures requiring interpolated pricing target_maturities = np.array([1.5, 3.0, 4.0, 7.5]) interpolated_yields = np.interp(target_maturities, known_maturities, known_yields) for tenure, rate in zip(target_maturities, interpolated_yields): print(f"Tenure {tenure:>4}Y: Interpolated Benchmark Yield = {rate:.3%}")
UNIT 2: DATA VISUALIZATION USING MATPLOTLIB Matplotlib is the core 2D graphics library in the Python ecosystem. Developed by John D. Hunter, it provides both a procedural MATLAB-style interface (matplotlib.pyplot) and an Object-Oriented interface for granular canvas control.
- Matplotlib: Structural Anatomy Understanding Matplotlib requires distinguishing its hierarchical structural elements:
- Figure: The top-level bounding window or canvas upon which everything is drawn.
- Axes: The actual plotting area containing the coordinate space, data points, x/y axes, ticks, labels, and title. A single Figure can contain multiple sub-Axes (e.g., price chart above volume chart).
- Axis: The numerical scale lines setting data limits, generating ticks (major/minor), and tick labels.
- Core: Financial Charting Types
- Line: Plot (Price Time-Series)
- Function: plt.plot(x, y)
- Financial Use: Visualizing continuous historical closing prices, 50-day and 200-day Simple Moving Average (SMA) trend crossovers, and NAV growth paths over multi-year horizons.
- Bar: Chart (Comparative Performance)
- Function: plt.bar(categories, values)
- Financial Use: Comparing quarterly revenue, profit before tax, and EPS growth across competing commercial banks or corporate peers.
- Pie: Chart (Asset Allocation)
- Function: plt.pie(sizes, labels, autopct)
- Financial Use: Illustrating portfolio capital distribution across broad asset classes (Equities,
Fixed Income, Real Estate, Liquid Cash) with callout wedges.
- Histogram (Return: Distributions)
- Function: plt.hist(data, bins)
- Financial Use: Analyzing the frequency distribution of daily asset returns to inspect tail risk, skewness, and deviations from the normal Gaussian bell curve.
- Multi-Panel: Executive Financial Dashboard Scripting import matplotlib.pyplot as plt # Simulating 100 Trading Sessions np.random.seed(42) days = np.arange(1, 101) prices = 1000 + np.cumsum(np.random.normal(1.2, 10.0, 100)) volumes = np.random.randint(100000, 500000, size=100) returns = np.diff(prices) / prices[:-1] # Multi-Panel Canvas Layout (2x1 Subplots: Price above Volume) fig, (ax1, ax2) = plt.subplots(nrows=2, ncols=1, figsize=(10, 8), sharex=True, gridspec_kw= {'height_ratios': [3, 1]}, dpi=100) # Panel 1: Price and Trend Crossover ax1.plot(days, prices, color="#0052cc", label="NIFTY Index Close", linewidth=2) ax1.set_title("Executive Technical Analysis: Price Trend & Liquidity Volume", fontsize=13, fontweight="bold") ax1.set_ylabel("Price (INR)", fontsize=11) ax1.grid(True, linestyle=":", alpha=0.6) ax1.legend(loc="upper left") # Panel 2: Volume Subplot ax2.bar(days, volumes, color="#42526e", width=0.8, alpha=0.7) ax2.set_ylabel("Volume (Shares)", fontsize=10) ax2.set_xlabel("Trading Session Day", fontsize=11) ax2.grid(True, linestyle=":", alpha=0.6) plt.tight_layout() # plt.savefig("executive_dashboard.png", dpi=300) # plt.show()
- Visualizing: Value at Risk (VaR) and Tail Risk Density Asset managers must present tail loss risks clearly to investment committees. Shading the distribution area below the 5% VaR threshold using ax.fill_between() highlights non-Gaussian downside risk: # Plotting Value at Risk (VaR) Area using Matplotlib returns_sample = np.random.normal(0.0005, 0.015, 2500) var_cutoff = np.percentile(returns_sample, 5) fig, ax = plt.subplots(figsize=(9, 5), dpi=100) count, bins, ignored = ax.hist(returns_sample, bins=50, density=True, color="#cbd5e1", edgecolor="#94a3b8") # Shading 5% Extreme Loss Tail in Red tail_mask = bins <= var_cutoff ax.axvline(var_cutoff, color="#d9381e", linestyle="--", linewidth=2, label=f"95% Daily VaR ({var_cutoff:.2%})") ax.set_title("Empirical Return Distribution with 95% Value at Risk (VaR)", fontsize=13, fontweight="bold") ax.set_xlabel("Daily Percentage Return", fontsize=11) ax.set_ylabel("Probability Density", fontsize=11) ax.legend(loc="upper right") ax.grid(True, linestyle=":", alpha=0.6)
UNIT 3: ANALYZING FINANCIAL DATA USING PANDAS Pandas (Python Data Analysis Library) is the primary toolkit for financial data engineering, time-series alignment, and econometric tabular analysis. Built directly on top of NumPy, Pandas provides two primary labeled data structures: the 1-dimensional Series and the 2-dimensional DataFrame.
- Pandas: Series vs DataFrame Architecture Feature Dimension Pandas Series Pandas DataFrame Dimensionality & Shape 1-Dimensional labeled array: (N,). 2-Dimensional tabular spreadsheet structure: (N, M).
Data Homogeneity Holds elements of a single data type. Heterogeneous: each column can possess a distinct dtype (floats, ints, dates, strings).
Financial Role Represents a single variable (e.g., closing prices, volume series, daily returns).
Represents an entire market dataset (Open, High, Low, Close, Volume, Turnover, PE ratio).
Index Architecture Single axis label index (e.g., trading dates).
- Dual axis labels: Row Index (dates/records) and Column Index (field headers).
- DataFrame: Creation, Slicing & Financial Data Ingestion import pandas as pd # Creating a Financial Market DataFrame data = { "Ticker": ["RELIANCE", "TCS", "HDFCBANK", "INFY", "ICICIBANK"], "Close_Price": [2850.50, 3920.00, 1540.25, 1425.80, 1080.00], "Market_Cap_Cr": [1928000, 1418000, 1172000, 592000, 758000], "PE_Ratio": [26.4, 29.8, 18.5, 24.2, 17.1], "Dividend_Yield": [0.35, 1.25, 1.10, 2.45, 0.95] } df_stocks = pd.DataFrame(data) # 1. Structural Exploration print(df_stocks.head(3)) # Displays top 3 rows print(df_stocks.info()) # Memory usage, dtypes, non-null counts print(df_stocks.describe()) # Summary statistics (mean, std, percentiles) # 2. Indexing: .loc (Label-based) vs .iloc (Position-based) top_stock_pe = df_stocks.loc[0, "PE_Ratio"] # 26.4 subset_matrix = df_stocks.iloc[0:2, 1:3] # First 2 rows, columns 1 and 2 # 3. Financial Screening: Value Investing Filter (PE < 20 and Div Yield > 1.0%) value_picks = df_stocks[(df_stocks["PE_Ratio"] < 20.0) & (df_stocks["Dividend_Yield"] >= 1.0)] print("FILTERED VALUE EQUITIES: ", value_picks[["Ticker", "Close_Price", "PE_Ratio"]])
- Missing: Data Cleaning & Financial Time-Series Transformations Real-world financial data contains gaps due to public holidays, exchange halts, and communication latency.
- Pandas provides robust imputation tools: .isna().sum(): Identifies the total count of missing null values per column. .dropna(): Removes entire rows containing missing data points. .ffill() (Forward Fill): Propagates the last valid observed price forward. This is the industry standard for financial time-series, reflecting the reality that an asset's price remains unchanged over a holiday until the next trading session opens. .pct_change(): Calculates percentage returns: df['Daily_Return'] = df['Close_Price'].pct_change(). .rolling(window=N).mean(): Computes moving averages across sliding temporal windows.
- Logarithmic vs: Simple Percentage Returns in Quantitative Finance In empirical asset pricing, choosing between simple percentage returns and continuous logarithmic returns is critical:
Return Formulations:
- Simple Return: R_t = (P_t - P_{t-1}) / P_{t-1} = (P_t / P_{t-1}) - 1 — Advantage: Cross-sectional aggregation. Portfolio return is exactly equal to the weighted sum of simple asset returns.
- Logarithmic Return: r_t = ln(P_t / P_{t-1}) = ln(P_t) - ln(P_{t-1}) — Advantage: Multi-period time-additivity. The total return over N years is simply the arithmetic sum of annual log returns: r_{0,N} = sum(r_t). # Computing Both Simple and Log Returns in Pandas df_prices = pd.DataFrame({ "Date": pd.date_range(start="2025-01-01", periods=5, freq="B"), "Price": [100.0, 105.0, 102.0, 108.0, 112.0] }).set_index("Date") # Simple Percentage Returns df_prices["Simple_Return"] = df_prices["Price"].pct_change() # Logarithmic Returns using NumPy np.log() df_prices["Log_Return"] = np.log(df_prices["Price"] / df_prices["Price"].shift(1)) print(df_prices)
- Resampling &: Frequency Aggregation for Tick and OHLC Bars In financial algorithmic trading, intraday data arriving in raw 1-minute chunks must be resampled into 15minute, hourly, or daily bars using Pandas .resample(): # Resampling Intraday Ticks to Form Daily OHLCV Bars minute_ticks = pd.DataFrame({ "Timestamp": pd.date_range(start="2025-03-01 09:15", periods=375, freq="min"), "Price": 1000.0 + np.cumsum(np.random.normal(0.05, 0.5, 375)), "Volume": np.random.randint(10, 500, size=375) }).set_index("Timestamp") # Aggregating to Hourly OHLC Bars hourly_bars = minute_ticks.resample("1h").agg({ "Price": ["first", "max", "min", "last"], "Volume": "sum" }) hourly_bars.columns = ["Open", "High", "Low", "Close", "Volume"] print("RESAMPLED HOURLY OHLC BARS: ", hourly_bars.head(4))
- Peak-to-Trough: Drawdown & Underwater Analysis in Pandas Institutional investors scrutinize Maximum Drawdown (MDD) to evaluate capital preservation during bear markets: # Automated Drawdown Engine in Pandas daily_returns = pd.Series([0.02, -0.01, -0.04,
- 0.03, 0.05, 0.01, -0.02]) # Step 1: Compute Cumulative Wealth Index starting from 1.0 wealth_index = (1 + daily_returns).cumprod() # Step 2: Compute Historical High-Water Mark (HWM) high_water_mark = wealth_index.cummax() # Step 3: Compute Daily Drawdown Series drawdown = (wealth_index - high_water_mark) / high_water_mark max_drawdown = drawdown.min() print(f"Historical High-Water Peak: {high_water_mark.iloc[-1]:.4f}") print(f"Maximum Peak-to-Trough Drawdown (MDD): {max_drawdown:.2%}")
- Multi-Sector: GroupBy Aggregation & Factor Attribution In institutional asset allocation, quantitative portfolio managers group stocks by industrial sectors to evaluate sector concentration and performance attribution. Pandas .groupby() enables multi-metric aggregation: # Sector Attribution and Aggregated Risk Metrics in Pandas df_portfolio = pd.DataFrame({ "Ticker": ["TCS", "INFY", "HDFCBANK", "ICICIBANK", "RELIANCE", "ONGC"], "Sector": ["IT", "IT", "Banking", "Banking", "Energy", "Energy"], "Weight": [0.20, 0.15, 0.25, 0.15, 0.15, 0.10], "Annual_Return": [0.18, 0.14, 0.12, 0.16, 0.22, 0.08], "Volatility": [0.19, 0.21, 0.17, 0.18, 0.24, 0.26] }) # Computing Sector Exposure and Weighted Performance sector_summary = df_portfolio.groupby("Sector").agg( Total_Weight=("Weight", "sum"),
Average_Return=("Annual_Return", "mean"), Average_Risk=("Volatility", "mean") ) sector_summary["Sharpe_Proxy"] = sector_summary["Average_Return"] / sector_summary["Average_Risk"] print("SECTOR EXPOSURE & PERFORMANCE ATTRIBUTION: ", sector_summary)
UNIT 4: STATISTICAL GRAPHICS USING SEABORN Seaborn is a high-level statistical data visualization library built directly on top of Matplotlib and integrated with Pandas DataFrames. While Matplotlib requires extensive boilerplate code to format axes and legends,
Seaborn automates statistical aggregation, distribution estimation, and sophisticated color mapping.
- Key: Visualizations for Quantitative Finance
- Distribution: Plots (sns.histplot)
- Mechanics: Combines frequency histograms with Kernel Density Estimation (KDE) curves.
- Financial Utility: Directly exposes whether security returns exhibit negative skewness (crash risk) or fat tails (leptokurtosis) exceeding normal distribution models.
- Box &: Violin Plots (sns.boxplot)
- Mechanics: Displays median, interquartile range (IQR), and statistical outlier dots beyond 1.5 × IQR.
- Financial Utility: Compares risk-return dispersion and extreme drawdown vulnerabilities across distinct economic sectors (e.g., Banking vs IT vs Pharma).
- Correlation: Heatmaps (sns.heatmap): The Cornerstone of Modern Portfolio Theory Under Harry Markowitz's Modern Portfolio Theory (MPT), the primary driver of portfolio risk reduction is the correlation coefficient between constituent assets. Seaborn's heatmap() provides an executive visual matrix displaying pairwise correlations: import seaborn as sns # Generating Multi-Asset Correlation Matrix daily_returns_df = pd.DataFrame({ "NIFTY_50": np.random.normal(0.0005, 0.012, 100), "GOLD_ETF": np.random.normal(0.0002, 0.008, 100), "GOVT_BONDS": np.random.normal(0.0001, 0.004, 100), "CRUDE_OIL": np.random.normal(0.0003, 0.022, 100), "TECH_INDEX": np.random.normal(0.0006, 0.016, 100) }) # Calculate Pearson Correlation Matrix correlation_matrix = daily_returns_df.corr() # Masking Upper Triangle for Publication Clarity mask = np.triu(np.ones_like(correlation_matrix, dtype=bool)) # Plotting Executive Correlation Heatmap plt.figure(figsize=(8, 6), dpi=100) sns.heatmap( correlation_matrix, mask=mask, # Clean display omitting redundant duplicate mirror annot=True, # Display numerical coefficients inside cells fmt=".2f", # Format to 2 decimal places cmap="coolwarm", # Diverging colormap: Red = +1.0, Blue = -1.0 vmin=-1.0, vmax=1.0, # Fixed statutory correlation scale linewidths=1.0, linecolor="#ffffff" ) plt.title("Multi-Asset Portfolio Correlation Matrix (Diversification Audit)", fontsize=13, fontweight="bold", pad=10) # plt.show()
- Regression &: Bivariate Risk Modeling with Seaborn To evaluate a stock's sensitivity to macroeconomic index movements, quantitative analysts plot linear regression scatterplots using sns.regplot(). The slope of the resulting fitted line represents the stock's empirical Beta (Systematic Risk): # Visualizing Stock Beta via Seaborn Regression Plot market_returns = np.random.normal(0.0004, 0.010, 150) # Stock with Beta = 1.35 and idiosyncratic noise stock_returns = 0.0002 + 1.35 * market_returns + np.random.normal(0, 0.005, 150) df_beta = pd.DataFrame({"NIFTY_Market_Return": market_returns, "Stock_Return": stock_returns}) plt.figure(figsize=(8, 5), dpi=100) sns.regplot( data=df_beta, x="NIFTY_Market_Return", y="Stock_Return", scatter_kws={"color": "#0052cc", "alpha": 0.6}, line_kws={"color": "#d9381e", "linewidth": 2} ) plt.title("Empirical Stock Beta Estimation (CAPM Regression)", fontsize=12, fontweight="bold") plt.xlabel("Market Return (NIFTY 50)", fontsize=10) plt.ylabel("Asset Return (Equity Security)", fontsize=10) plt.grid(True, linestyle=":", alpha=0.6) # plt.show()
- Markowitz: Efficient Frontier Simulation & Visualization The culmination of Modern Portfolio Theory is the Efficient Frontier: the set of optimal portfolios that offer the highest expected return for a defined level of risk. By generating 2,500 random Dirichlet portfolio weight allocations in NumPy, computing their respective Sharpe ratios, and visualizing the multi-dimensional riskreturn space in Matplotlib/Seaborn, portfolio managers isolate optimal asset weights: # Simulating the Markowitz Efficient Frontier in Python num_portfolios = 2500 num_assets = 4 mean_returns = np.array([0.14, 0.11, 0.08, 0.16]) cov_matrix = np.array([ [0.035, 0.012, 0.008, 0.015], [0.012, 0.025, 0.006, 0.010], [0.008, 0.006, 0.015, 0.005], [0.015, 0.010, 0.005, 0.045] ]) risk_free_rate = 0.06 results = np.zeros((3, num_portfolios)) weights_record = [] for i in range(num_portfolios): # Generating random weights summing to exactly 1.0 w = np.random.dirichlet(np.ones(num_assets)) weights_record.append(w) p_return = np.dot(w, mean_returns) p_std = np.sqrt(w.T @ cov_matrix @ w) p_sharpe = (p_return - risk_free_rate) / p_std results[0, i] = p_std results[1, i] = p_return results[2, i] = p_sharpe # Identifying Max Sharpe Ratio and Min Volatility Portfolios max_sharpe_idx = np.argmax(results[2]) min_vol_idx = np.argmin(results[0]) # Visualizing Efficient Frontier plt.figure(figsize=(9, 6), dpi=100) scatter = plt.scatter(results[0, :], results[1, :], c=results[2, :], cmap="viridis", alpha=0.7, marker="o", s=15) plt.colorbar(scatter, label="Sharpe Ratio (Rf = 6.0%)") # Marking Benchmark Portfolios plt.scatter(results[0, max_sharpe_idx], results[1, max_sharpe_idx], marker="*", color="red", s=250, label="Max Sharpe Portfolio") plt.scatter(results[0, min_vol_idx], results[1, min_vol_idx], marker="P", color="orange", s=200, label="Min Volatility Portfolio") plt.title("Markowitz Efficient Frontier & Portfolio Risk-Return Spectrum", fontsize=13, fontweight="bold") plt.xlabel("Portfolio Annualized Volatility (Risk)", fontsize=11) plt.ylabel("Portfolio Expected Annual Return", fontsize=11) plt.legend(loc="upper left") plt.grid(True, linestyle=":", alpha=0.6) # plt.show()
- ENTERPRISE CASE BENCHMARK: WEALTH MANAGEMENT ANALYTICS AUTOMATION
- Malabar Horizon Wealth Partners: A boutique private wealth management firm in Calicut overseeing ₹320 Crores in client mandates previously generated monthly client investment review decks by manually copy-pasting tables from Excel into PowerPoint presentations. Preparing quarterly portfolio health cards took four junior analysts over 10 working days, resulting in recurring transcription errors.
- By implementing an automated Python reporting pipeline using NumPy, Pandas, and Seaborn:
- Pandas scripts automatically ingest historical daily NAV feeds, compute rolling Sharpe ratios, and forward-fill weekend transaction dates.
- Matplotlib and Seaborn generate customized vector visual charts: equity asset growth line plots, sector allocation pie charts, and portfolio correlation heatmaps.
- The entire client reporting pack generation was reduced from 10 days of manual labor to an automated 45-second script run.
- Business Result: 100% mathematical audit accuracy achieved, eliminating human transposition errors and saving ₹14 Lakhs in annual administrative overhead.
MODULE III COMPREHENSIVE MASTERY SUMMARY EXECUTIVE SUMMARY NUMPY LINEAR ALGEBRA + PANDAS DATA ENGINEERING + MATPLOTLIB/SEABORN GRAPHICS = QUANTITATIVE MASTERY Library Domain Core Technical Architecture Strategic Financial Role NumPy (Numerical Python) ndarray, contiguous memory, vectorized arithmetic, broadcasting, mathematical ufuncs.
High-speed financial matrix math, Monte Carlo stochastic simulations, portfolio linear algebra.
Matplotlib Engine Figure & Axes canvas, procedural pyplot vs Object-Oriented APIs, vector export.
Visualizing historical price trends, moving average crossovers, asset allocation pie charts.
Pandas Data Engineering Series, DataFrames, .loc/.iloc,
Boolean filters, forward filling, rolling stats. Financial time-series data cleansing, equity screening, daily return computation, corporate data audits.
Seaborn Statistical Graphics KDE distribution curves, categorical box/violin plots, annotated heatmaps (sns.heatmap).
Evaluating portfolio tail risk, dispersion of industry returns, and pairwise asset diversification.
Download Module 3 Notes (PDF)
Calicut University • FYUGP 2024 Syllabus
Finished this module?
Continue reading the next module or return to the subject overview.