Lesson 12 · Finance and Stock Market Analytics
Understanding OHLCV Data in Finance: Open, High, Low, Close, and Volume Explained
In this lesson, we will explore the structure, meaning, and use of OHLCV data in finance and stock market analytics. OHLCV data describes daily price and…
- CourseFinance and Stock Market Analytics
- Lesson12 of 16
- Video24 min
- FormatJupyter notebook · 16 code cells
- Data1 dataset
What you'll learn
- What is OHLCV Data?
- How is OHLCV Data Structured?
- Why Does OHLCV Matter in Stock Analytics?
- Beginner Example 1: Filtering by Ticker
- Beginner Example 2: Filtering by Date
- Beginner Example 3: Sorting by Price or Volume
- Intermediate Example 1: Pivoting OHLCV to Wide Format
- Intermediate Example 2: Calculating Daily Returns
Datasets used in this lesson
Save these next to the notebook. In Google Colab, upload them with the 📁 icon on the left first.
📓 Full notebook
Download .ipynbUnderstanding OHLCV Data (Open, High, Low, Close, Volume)#
- In this lesson, we will explore the structure, meaning, and use of OHLCV data in finance and stock market analytics.
- OHLCV data describes daily price and trading activity for stocks and is fundamental to financial analysis.
- You will learn to load, inspect, filter, reshape, and analyze real OHLCV data for multiple companies using Python.
- By the end, you will understand how to apply OHLCV to solve typical finance problems like return calculation, simple signals, and basic error handling.
import pandas as pd
import yfinance as yf
import numpy as np
import warnings
warnings.filterwarnings('ignore')
What is OHLCV Data?#
- OHLCV stands for Open, High, Low, Close, and Volume.
- Each value shows a different aspect of stock price and trading for a single day.
- Open: Price at the start of the trading day.
- High: Highest price traded during the day.
- Low: Lowest price traded during the day.
- Close: Final price at the end of the trading day.
- Volume: Number of shares traded during the day.
- OHLCV data is usually recorded for each stock and each day on the market.
How is OHLCV Data Structured?#
- In Python, OHLCV is commonly managed in DataFrames, where each row is a day and ticker.
- Columns include Date, Ticker, Open, High, Low, Close, and Volume.
- Multi-ticker data can be stored in long (tidy) or wide (pivot) formats.
- Beginners often confuse column orders, ticker positions, or try to flatten indices incorrectly.
Why Does OHLCV Matter in Stock Analytics?#
- OHLCV enables return, volatility, drawdown, and pattern calculations.
- It powers almost all charting, trading signals, and portfolio analytics.
- Clean OHLCV understanding is required to interpret any price-based insight in finance.
# Load multi-ticker OHLCV data for 5 major US tech companies (1 year)
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))
Beginner Example 1: Filtering by Ticker#
- To get OHLCV for a single stock on all trading days, filter on the Ticker column.
- This lets you analyze just one company's price and volume movements.
# Select only Apple (AAPL) data from the long OHLCV DataFrame
aapl_ohlcv = ohlcv[ohlcv['Ticker'] == 'AAPL']
print(aapl_ohlcv.head(5))
Beginner Example 2: Filtering by Date#
- You can select rows for a specific date or a range of dates.
- This is useful for finding important trading days or events.
# Select TSLA data for the first trading week
first_week = ohlcv[(ohlcv['Ticker'] == 'TSLA') & (ohlcv['Date'] <= ohlcv[ohlcv['Ticker']=='TSLA']['Date'].iloc[4])]
print(first_week)
Beginner Example 3: Sorting by Price or Volume#
- To find most volatile or highest volume days, sort rows by High, Low, or Volume.
- Sorting helps discover outlier days and trading spikes.
# Find top 3 highest volume days for Google (GOOGL)
googl = ohlcv[ohlcv['Ticker'] == 'GOOGL']
top_vol = googl.sort_values('Volume', ascending=False).head(3)
print(top_vol[['Date','Volume','Close']])
Intermediate Example 1: Pivoting OHLCV to Wide Format#
- Sometimes, analysts want one row per date with a separate column per ticker.
- Pivoting reorganizes tidy OHLCV into a 'wide' price table for comparisons or charts.
# Pivot to create a wide Close price table (dates as rows, tickers as columns)
close_wide = ohlcv.pivot(index='Date', columns='Ticker', values='Close')
print(close_wide.head())
Intermediate Example 2: Calculating Daily Returns#
- Financial analysis often starts with returns, not just prices.
- You can calculate percent changes in Close prices to find daily returns per stock.
# Calculate daily returns for each ticker
ohlcv['Return'] = ohlcv.groupby('Ticker')['Close'].pct_change() * 100
print(ohlcv[['Date','Ticker','Close','Return']].head(8))
Intermediate Example 3: Filtering Volatile Trading Days#
- Large differences between High and Low signal volatility.
- Find all days where the intraday range exceeds a threshold (e.g. 6%).
# Find all AMZN days where High-Low > 6% of Open price
amzn = ohlcv[ohlcv['Ticker']=='AMZN'].copy()
amzn['RangePct'] = (amzn['High'] - amzn['Low']) / amzn['Open'] * 100
volatile = amzn[amzn['RangePct'] > 6]
print(volatile[['Date','Open','High','Low','RangePct']].head(4))
Advanced Example 1: Querying With Multiple Criteria#
- Analysts often need to combine filters, such as high Volume and large price drops.
- This allows targeting rare or impactful market events.
# Top 5 TSLA days with both huge Volume and negative returns
tsla = ohlcv[ohlcv['Ticker'] == 'TSLA']
threshold = tsla['Volume'].quantile(0.95)
big_down = tsla[(tsla['Volume'] > threshold) & (tsla['Return'] < -4)]
print(big_down[['Date','Volume','Return','Close']].head())
Advanced Example 2: Visualizing OHLCV Data#
- Visualization reveals trends, cycles, and anomalies.
- You can use matplotlib to plot OHLC, closing price, or trading volume series.
import matplotlib.pyplot as plt
# Plot AAPL closing price and volume on two axes
aapl = ohlcv[ohlcv['Ticker']=='AAPL']
fig, ax1 = plt.subplots(figsize=(9,4))
ax1.plot(aapl['Date'], aapl['Close'], color='b', label='Close Price')
ax1.set_ylabel('Price (USD)', color='b')
ax2 = ax1.twinx()
ax2.bar(aapl['Date'], aapl['Volume'], alpha=0.2, color='r', label='Volume')
ax2.set_ylabel('Volume', color='r')
plt.title('AAPL: Close Price and Volume (1 year)')
plt.show()
Advanced Example 3: Rolling Statistics for Volatility#
- Financial volatility is often measured with rolling averages or standard deviations.
- A rolling standard deviation of returns helps spot calm versus turbulent periods.
# Compute 20-day rolling standard deviation of returns for MSFT
msft = ohlcv[ohlcv['Ticker'] == 'MSFT'].copy()
msft['RollStd'] = msft['Return'].rolling(20).std()
print(msft[['Date','Return','RollStd']].tail(5))
Error Handling: Missing Data and NaNs in OHLCV#
- Stock markets do not trade on weekends and some days have missing data.
- OHLCV manipulations can introduce NaN values.
- It is important to detect and handle missing values to avoid incorrect results.
# Count NaNs in each column after all calculations so far
na_counts = ohlcv.isna().sum()
print('Missing values per column:')
print(na_counts)
# Drop rows with any missing data (if desired)
clean_ohlcv = ohlcv.dropna()
print('OHLCV after dropping missing:', clean_ohlcv.shape)
Common Best Practices for OHLCV Data in Analytics#
- Always check for missing or duplicate data before analysis.
- Use clear column names and document your data structures.
- Keep your code modular and reusable for other tickers or new data.
- Set random seed for reproducibility (e.g. np.random.seed(42)).
# Check for duplicate Date/Ticker pairs
dupes = ohlcv.duplicated(subset=['Date','Ticker']).sum()
print(f'Total duplicate date/ticker rows: {dupes}')
End-to-End Example: Identify Best-Performing Stock Over the Year#
- Let us combine our skills: load, clean, pivot, compute returns, and find the winner.
- We want to know which of our five tech stocks achieved the highest total return.
# Step 1: Clean OHLCV DataFrame
df = ohlcv.dropna()
# Step 2: Pivot to wide Close price table
wide = df.pivot(index='Date', columns='Ticker', values='Close')
# Step 3: Calculate total return for each ticker (percent change from start to end)
total_ret = 100.0 * (wide.iloc[-1] / wide.iloc[0] - 1)
best = total_ret.idxmax()
print('Total return by ticker (%):')
print(total_ret.round(2))
print(f'Best performing stock: {best}')
filename = 'best_stock_report.txt'
with open(filename, 'w') as f:
f.write('Total return by ticker (%)\n')
for ticker, val in total_ret.round(2).items():
f.write(f'{ticker}: {val}%\n')
f.write(f'\nBest performing stock: {best}\n')
print(f'Results saved to {filename}')
Congratulations! You now understand OHLCV data and how to analyze it for finance and stock market analytics.#
- Review and practice filtering, pivoting, and return calculations using real OHLCV data.
- Try more advanced analytics or subscribe to our YouTube channel for deeper tutorials on stock data.
Found this useful?
All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.



