Mathew K Analytics

Lesson 46 · Finance and Stock Market Analytics

Introduction to Time Series in Finance: Key Concepts and Applications

In this lesson, we will explore the basics of financial time series and their applications in analyzing the stock market. You will learn to import real…

⬇ Download notebookOpen in Colab ↗

What you'll learn

Data

No separate download needed — the notebook creates or downloads everything it uses.

📓 Full notebook

Download .ipynb

Introduction to Time Series in Finance#

  • In this lesson, we will explore the basics of financial time series and their applications in analyzing the stock market.
  • You will learn to import real stock price data, inspect its structure, and perform key time series analyses using Python.
  • Time series analysis is essential for understanding the behavior of markets over time, evaluating risk, and creating trading strategies.
  • We will move from basic data exploration to advanced analytics and solve a hands-on finance problem step by step.
  • By the end, you will know how to manipulate, visualize, and extract insights from real financial time series data.
import pandas as pd
import numpy as np
import yfinance as yf
import warnings
warnings.filterwarnings('ignore')

Understanding Financial Time Series Data#

  • A time series is a sequence of data points recorded at regular time intervals.
  • In finance, time series often capture daily stock prices, trading volume, or returns.
  • Each row typically represents the value of a financial metric (like close price) for a specific date.
  • Data can be organized in 'long' format (one row per date and ticker) or 'wide' format (one column per ticker).
  • Beginners often struggle with converting between these formats and handling missing data.
# Beginner Example 1: Load stock prices for multiple tickers
tickers = ['AAPL', 'MSFT', 'GOOGL', 'AMZN', 'TSLA']
df = yf.download(tickers, period='1y', auto_adjust=True, progress=False)
df = df['Close'].reset_index()
df.columns.name = None
print(df.shape)
print(df.head(3))
(252, 6)
        Date        AAPL        AMZN       GOOGL        MSFT        TSLA
0 2025-07-14  207.795639  225.690002  181.043518  499.033936  316.899994
1 2025-07-15  208.283707  226.350006  181.482269  501.811768  310.779999
2 2025-07-16  209.329544  223.190002  182.449524  501.613342  321.670013
# Beginner Example 2: Load daily returns for the SPY ETF
data = yf.download('SPY', period='2y', auto_adjust=True, progress=False)
spy_df = data[['Close','Volume']].reset_index()
spy_df.columns = ['date','price','volume']
spy_df['daily_return'] = (spy_df['price'].pct_change() * 100).round(4)
spy_df = spy_df.dropna().reset_index(drop=True)
print(spy_df.shape)
print(spy_df.head(3))
(500, 4)
        date       price    volume  daily_return
0 2024-07-16  551.797058  36475300        0.5930
1 2024-07-17  544.060242  57119000       -1.4021
2 2024-07-18  539.879089  56270400       -0.7685
# Beginner Example 3: Load multi-ticker OHLCV 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))
(1260, 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
# Beginner Example 4: Select pricing data for a single ticker from long format
aapl_prices = ohlcv[ohlcv['Ticker'] == 'AAPL']
print(aapl_prices.shape)
print(aapl_prices.head(3))
(252, 7)
         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.283691  211.052705  208.094440  208.393257  42296300
10 2025-07-16   AAPL  209.329544  211.560683  207.815546  209.468990  47490500
# Beginner Example 5: Convert long to wide format for close prices
wide_prices = ohlcv.pivot(index='Date', columns='Ticker', values='Close')
print(wide_prices.shape)
print(wide_prices.head(3))
(252, 5)
Ticker            AAPL        AMZN       GOOGL        MSFT        TSLA
Date                                                                  
2025-07-14  207.795624  225.690002  181.043518  499.033936  316.899994
2025-07-15  208.283691  226.350006  181.482269  501.811768  310.779999
2025-07-16  209.329544  223.190002  182.449524  501.613373  321.670013
# Intermediate Example 1: Plot the closing prices of all five stocks
import matplotlib.pyplot as plt
plt.figure(figsize=(12,6))
for tkr in tickers:
    plt.plot(wide_prices.index, wide_prices[tkr], label=tkr)
plt.title('Close Prices of Major Tech Stocks (1Y)')
plt.xlabel('Date')
plt.ylabel('Price (USD)')
plt.legend()
plt.show()
No description has been provided for this image
# Intermediate Example 2: Compute daily returns for all tickers (wide format)
returns = wide_prices.pct_change().dropna() * 100
returns = returns.round(2)
print(returns.head(3))
Ticker      AAPL  AMZN  GOOGL  MSFT  TSLA
Date                                     
2025-07-15  0.23  0.29   0.24  0.56 -1.93
2025-07-16  0.50 -1.40   0.53 -0.04  3.50
2025-07-17 -0.07  0.31   0.33  1.20 -0.70
# Intermediate Example 3: Compute rolling 20-day volatility (standard deviation)
vol_20d = returns.rolling(window=20).std().round(2)
print(vol_20d.tail(3))
Ticker      AAPL  AMZN  GOOGL  MSFT  TSLA
Date                                     
2026-07-10  2.21  2.17   2.03  2.36  3.83
2026-07-13  2.20  2.15   2.05  2.35  3.78
2026-07-14  2.17  2.13   2.10  2.37  3.75
# Intermediate Example 4: Correlation between the daily returns of stocks
corr_matrix = returns.corr()
print(corr_matrix)
Ticker      AAPL      AMZN     GOOGL      MSFT      TSLA
Ticker                                                  
AAPL    1.000000  0.317928  0.276804  0.187754  0.242334
AMZN    0.317928  1.000000  0.419147  0.330452  0.334105
GOOGL   0.276804  0.419147  1.000000  0.096478  0.375617
MSFT    0.187754  0.330452  0.096478  1.000000  0.176460
TSLA    0.242334  0.334105  0.375617  0.176460  1.000000
# Intermediate Example 5: Detect missing data and handle it
print(ohlcv.isnull().sum())
ohlcv_clean = ohlcv.dropna()
print('Data after dropping missing rows:', ohlcv_clean.shape)
Date      0
Ticker    0
Close     0
High      0
Low       0
Open      0
Volume    0
dtype: int64
Data after dropping missing rows: (1260, 7)
# Advanced Example 1: Resample daily returns to monthly returns
monthly_returns = wide_prices.resample('M').last().pct_change().dropna() * 100
monthly_returns = monthly_returns.round(2)
print(monthly_returns.head(3))
Ticker       AAPL   AMZN  GOOGL  MSFT   TSLA
Date                                        
2025-08-31  11.96  -2.18  10.95 -4.87   8.30
2025-09-30   9.69  -4.12  14.28  2.22  33.20
2025-10-31   6.18  11.23  15.67 -0.03   2.66
# Advanced Example 2: Compute 50-day moving averages as a trend indicator
ma_50 = wide_prices.rolling(window=50).mean()
print(ma_50.tail(3))
Ticker            AAPL      AMZN       GOOGL        MSFT        TSLA
Date                                                                
2026-07-10  297.726962  254.0346  372.621688  403.328766  409.196399
2026-07-13  298.674736  253.7200  372.677266  402.677713  409.635599
2026-07-14  299.561031  253.3718  372.182460  402.250839  409.913099
# Advanced Example 3: Find the best/worst single-day return for each ticker
best_returns = returns.max()
worst_returns = returns.min()
print('Best single-day returns (%):')
print(best_returns)
print('Worst single-day returns (%):')
print(worst_returns)
Best single-day returns (%):
Ticker
AAPL     5.09
AMZN     9.58
GOOGL    9.96
MSFT     5.71
TSLA     8.46
dtype: float64
Worst single-day returns (%):
Ticker
AAPL    -6.12
AMZN    -8.27
GOOGL   -4.99
MSFT    -9.99
TSLA    -8.20
dtype: float64
# Advanced Example 4: Create trading signals using SMA crossover for AAPL
data = yf.download('AAPL', period='1y', auto_adjust=True, progress=False)
df_sma = data[['Close','Volume']].reset_index()
df_sma.columns = ['date','close','volume']
df_sma['sma20'] = df_sma['close'].rolling(20).mean().round(2)
df_sma['sma50'] = df_sma['close'].rolling(50).mean().round(2)
df_sma['signal'] = np.where(df_sma['sma20'] > df_sma['sma50'], 1, -1)
print(df_sma.tail(3))
          date       close    volume   sma20   sma50  signal
249 2026-07-10  315.320007  34132300  298.10  297.73       1
250 2026-07-13  317.309998  43257800  299.19  298.67       1
251 2026-07-14  315.089996  22800039  300.39  299.55       1
# Error Example: Wrong column name in resample
try:
    _ = spy_df.resample('M').last()['close']
except Exception as e:
    print('Error:', e)
Error: Only valid with DatetimeIndex, TimedeltaIndex or PeriodIndex, but got an instance of 'RangeIndex'
# Error Example: Handling NA values by forward filling
aapl_prices_ffill = aapl_prices.fillna(method='ffill')
print(aapl_prices_ffill.isnull().sum())
Date      0
Ticker    0
Close     0
High      0
Low       0
Open      0
Volume    0
dtype: int64

Best Practices for Financial Time Series#

  • Always check for missing values before any calculation.
  • Plot time series data frequently to catch outliers and errors.
  • Use long format for flexible filtering and grouping; use wide format for correlation and comparison.
  • Set a seed for reproducibility in simulations: np.random.seed(42).
  • Remember to handle time zones and market holidays carefully.
# End-to-end Problem: Identify the highest single-day loss for TSLA in the past year and plot it
np.random.seed(42)  # for reproducibility
tsla_prices = ohlcv[ohlcv['Ticker'] == 'TSLA'].copy()
tsla_prices['Return'] = tsla_prices['Close'].pct_change() * 100
worst_day = tsla_prices['Return'].idxmin()
print('Worst day for TSLA:', tsla_prices.loc[worst_day, 'Date'], 'Return:', round(tsla_prices.loc[worst_day, 'Return'],2), '%')
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 5))
plt.plot(tsla_prices['Date'], tsla_prices['Close'], label='TSLA Close')
plt.scatter(tsla_prices.loc[worst_day, 'Date'], tsla_prices.loc[worst_day, 'Close'], color='red', label='Worst Day')
plt.title('TSLA Closing Prices with Worst Single-Day Loss Highlighted')
plt.xlabel('Date')
plt.ylabel('Price (USD)')
plt.legend()
plt.show()
Worst day for TSLA: 2025-07-24 00:00:00 Return: -8.2 %
No description has been provided for this image

YouTube#

  • Learn more market analytics tips by checking out our channel!
  • Subscribe for the latest finance coding tutorials!

Found this useful?

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