Mathew K Analytics

Lesson 9 · Finance and Stock Market Analytics

Introduction to Pandas for Stock Data Analysis

Pandas is a powerful Python package for working with tabular data. Stock market data is naturally tabular and time-based, making it a great fit for Pandas.…

⬇ Download notebookOpen in Colab ↗

📓 Full notebook

Download .ipynb

Introduction to Pandas for Stock Data#

  • Pandas is a powerful Python package for working with tabular data.
  • Stock market data is naturally tabular and time-based, making it a great fit for Pandas.
  • In this lesson, you will learn how to load, inspect, and analyze real stock market data using Pandas.
  • We will use real world examples from large tech companies.
  • By the end, you will be able to answer questions and spot patterns in stocks with confidence.
import warnings
warnings.filterwarnings('ignore')

import pandas as pd
import yfinance as yf

What kind of stock data will we explore?#

  • We will work with real daily Open, High, Low, Close, and Volume (OHLCV) data.
  • Each day and ticker has its own row.
  • The data is in 'long format', with columns like Date, Ticker, Close, High, Low, Open, Volume.
  • Beginners often get confused by wide vs long format data.
  • MultiIndex data from yfinance can trick new users. We will work with a clean flattened table instead.
# Load real multi-ticker OHLCV stock data in long format
tickers = ['AAPL','MSFT','GOOGL','AMZN','TSLA']
ohlcv = yf.download(tickers, period='1y', auto_adjust=True, progress=False)
ohlcv = ohlcv.stack(future_stack=True).rename_axis(['Date','Ticker']).reset_index()
ohlcv.columns.name = None

print(ohlcv.shape)
print(ohlcv.head(3))
(1255, 7)
        Date Ticker       Close        High         Low        Open    Volume
0 2025-07-14   AAPL  207.795624  210.076583  206.719890  209.100445  38840100
1 2025-07-14   AMZN  225.690002  226.660004  224.240005  225.070007  35702600
2 2025-07-14  GOOGL  181.043518  183.147516  179.168861  180.495080  32536600

Core columns in our stock market dataset#

  • Date: The trading date (YYYY-MM-DD).
  • Ticker: The stock ticker symbol (for example, AAPL for Apple).
  • Open: The price at which the stock started trading that day.
  • High: The highest price that day.
  • Low: The lowest price that day.
  • Close: The price at the market close.
  • Volume: The number of shares traded that day.
  • Pay close attention to column meanings! They are vital for finance analysis.
# Example: View all available tickers in our OHLCV data
print(ohlcv['Ticker'].unique())
['AAPL' 'AMZN' 'GOOGL' 'MSFT' 'TSLA']
# Example: Select all rows for Apple (AAPL)
apple = ohlcv[ohlcv['Ticker'] == 'AAPL']
print(apple.head(2))
        Date Ticker       Close        High         Low        Open    Volume
0 2025-07-14   AAPL  207.795624  210.076583  206.719890  209.100445  38840100
5 2025-07-15   AAPL  208.283707  211.052720  208.094455  208.393273  42296300
# Example: What is the date range in our dataset?
print('First date:', ohlcv['Date'].min())
print('Last date:', ohlcv['Date'].max())
First date: 2025-07-14 00:00:00
Last date: 2026-07-13 00:00:00
# Example: Count the number of trading days for each ticker
counts = ohlcv.groupby('Ticker').size()
print(counts)
Ticker
AAPL     251
AMZN     251
GOOGL    251
MSFT     251
TSLA     251
dtype: int64

Intermediate: Pivot data to wide format for price comparison#

  • In real finance, you may want to compare closing prices across stocks on the same date.
  • Pandas 'pivot' allows you to reshape from long to wide format.
  • Rows become dates, columns become tickers, and values are selected columns (for example, Close).
  • Be careful: beginners sometimes confuse index and columns in pivots.
# Pivot: Create a wide table of close prices (dates vs tickers)
wide = ohlcv.pivot(index='Date', columns='Ticker', values='Close')
print(wide.head(2))
Ticker            AAPL        AMZN       GOOGL        MSFT        TSLA
Date                                                                  
2025-07-14  207.795624  225.690002  181.043518  499.033936  316.899994
2025-07-15  208.283707  226.350006  181.482269  501.811768  310.779999
# Example: Compute daily price change in percent for Apple
apple['Pct_Change'] = apple['Close'].pct_change() * 100
print(apple[['Date','Close','Pct_Change']].head(5))
         Date       Close  Pct_Change
0  2025-07-14  207.795624         NaN
5  2025-07-15  208.283707    0.234886
10 2025-07-16  209.329544    0.502122
15 2025-07-17  209.190094   -0.066617
20 2025-07-18  210.345505    0.552326

Intermediate: Filter for high price swings#

  • In risk management, traders look for days with unusually large price moves.
  • You can filter rows where percent change (up or down) exceeds 3 percent.
  • This is often used in volatility screening and backtesting.
# Filter Apple rows for large positive or negative price moves
swings = apple[apple['Pct_Change'].abs() > 3]
print(swings[['Date','Close','Pct_Change']])
           Date       Close  Pct_Change
85   2025-08-06  212.407349    5.090686
90   2025-08-07  219.160538    3.179358
95   2025-08-08  228.443741    4.235800
180  2025-09-03  237.797241    3.808983
205  2025-09-10  226.150192   -3.225954
240  2025-09-19  244.807404    3.203286
245  2025-09-22  255.357559    4.309574
315  2025-10-10  244.578064   -3.452205
345  2025-10-20  261.500153    3.943858
655  2026-01-20  246.242508   -3.455559
700  2026-02-02  269.509277    4.058102
740  2026-02-12  261.489105   -4.998174
750  2026-02-17  263.637115    3.166790
790  2026-02-27  263.936829   -3.213044
1010 2026-05-01  279.882141    3.239352
1140 2026-06-09  290.549988   -3.644631
1195 2026-06-25  275.149994   -6.117781
1200 2026-06-26  283.779999    3.136473
1220 2026-07-02  308.630005    4.840682

Advanced: Compute a rolling 20-day average closing price for Tesla#

  • Rolling means a moving window, often used by traders and analysts.
  • The average smooths out day-to-day noise, showing the trend.
  • Rolling analysis is used in technical indicators like moving averages.
  • Beginners often forget to .sort_values('Date') before rolling if data is unordered.
# Calculate a 20-day rolling mean for TSLA closing prices
tesla = ohlcv[ohlcv['Ticker'] == 'TSLA'].sort_values('Date')
tesla['SMA20'] = tesla['Close'].rolling(window=20).mean()
print(tesla[['Date','Close','SMA20']].tail(7))
           Date       Close       SMA20
1224 2026-07-02  393.450012  399.156998
1229 2026-07-06  419.769989  399.222997
1234 2026-07-07  402.899994  399.817996
1239 2026-07-08  394.059998  399.073495
1244 2026-07-09  406.549988  399.566995
1249 2026-07-10  407.760010  400.875496
1254 2026-07-13  391.894989  400.512746
# Advanced: Find the highest volume day for Google
google = ohlcv[ohlcv['Ticker'] == 'GOOGL']
max_vol = google.loc[google['Volume'].idxmax()]
print('Highest volume day for GOOGL:', max_vol['Date'])
print('Volume:', int(max_vol['Volume']))
Highest volume day for GOOGL: 2026-06-26 00:00:00
Volume: 114706300
# Advanced: Find all days where Amazon closed higher than both Apple and Tesla
pivot_close = ohlcv.pivot(index='Date', columns='Ticker', values='Close')
mask = (pivot_close['AMZN'] > pivot_close['AAPL']) & (pivot_close['AMZN'] > pivot_close['TSLA'])
result = pivot_close[mask]
print(result[['AMZN','AAPL','TSLA']].head())
Empty DataFrame
Columns: [AMZN, AAPL, TSLA]
Index: []

Error handling: What if a ticker has missing data?#

  • In real markets, holidays and IPOs can cause missing trading days for some stocks.
  • Always check for missing values with pd.isna or .isnull.
  • You can fill or drop missing data depending on your business need.
# Detect missing (NA) values in the long OHLCV table
print(ohlcv.isnull().sum())
Date      0
Ticker    0
Close     0
High      0
Low       0
Open      0
Volume    0
dtype: int64
# Best practice: Always check your Date column type
print('Date column dtype:', ohlcv['Date'].dtype)
ohlcv['Date'] = pd.to_datetime(ohlcv['Date'])
print('After conversion:', ohlcv['Date'].dtype)
Date column dtype: datetime64[ns]
After conversion: datetime64[ns]

Common patterns in stock data analysis#

  • Filtering on ticker or date.
  • Calculating percent returns.
  • Creating moving averages.
  • Handling missing data wisely.
  • Pivoting to wide format for comparison.
  • Always document your steps as comments.
# Practice: Select Tesla closing prices during the last three months
last_3mo = tesla[tesla['Date'] >= (tesla['Date'].max() - pd.Timedelta(days=90))]
print(last_3mo[['Date','Close']].head())
          Date       Close
949 2026-04-14  364.200012
954 2026-04-15  391.950012
959 2026-04-16  388.899994
964 2026-04-17  400.619995
969 2026-04-20  392.500000
# End-to-end example: Identify top 2 up days for each ticker
top2 = ohlcv.copy()
top2['Pct_Change'] = top2.groupby('Ticker')['Close'].pct_change() * 100
ranks = top2.groupby('Ticker')['Pct_Change'].nlargest(2).reset_index()
result = top2.loc[ranks['level_1'], ['Date','Ticker','Close','Pct_Change']]
print(result.sort_values(['Ticker','Pct_Change'], ascending=[True, False]))
           Date Ticker       Close  Pct_Change
85   2025-08-06   AAPL  212.407349    5.090686
1220 2026-07-02   AAPL  308.630005    4.840682
391  2025-10-31   AMZN  244.220001    9.584493
931  2026-04-09   AMZN  233.649994    5.604517
1007 2026-04-30  GOOGL  384.570282    9.961702
182  2025-09-03  GOOGL  230.003860    9.136501
1203 2026-06-26   MSFT  372.970001    5.708136
1108 2026-05-29   MSFT  450.239990    5.445093
1209 2026-06-29   TSLA  411.839996    8.461722
954  2026-04-15   TSLA  391.950012    7.619440
 

Found this useful?

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