Mathew K Analytics

Lesson 1 · Finance and Stock Market Analytics

Introduction to Technical Analysis for Finance and Stock Market Analytics

This lesson explores how to use Python for real-world finance and stock market analytics. Finance and stock analytics are essential for understanding…

⬇ 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 Finance and Stock Market Analytics#

  • This lesson explores how to use Python for real-world finance and stock market analytics.
  • Finance and stock analytics are essential for understanding company valuation, risk, and trends.
  • We will use real datasets and solve practical analytics problems, from basic to advanced.
  • By the end, you will be able to load, analyze, and visualize financial data and extract actionable insights.
  • All examples use real data from yfinance and GitHub.
import warnings
warnings.filterwarnings('ignore')
import pandas as pd
import numpy as np
import yfinance as yf

Understanding the Data in Finance and Stock Market Analytics#

  • Financial data covers prices, fundamentals, and trading activity for companies and funds.
  • Data can come in 'wide' format (one column per ticker) or 'long' format (each row is date/ticker pair).
  • The structure of data impacts how you filter, reshape, and analyze it.
  • Common mistakes: flattening index incorrectly, mislabeling tickers, or misunderstanding real vs. synthetic data.
url = 'https://raw.githubusercontent.com/datasets/s-and-p-500-companies/main/data/constituents.csv'
sp500 = pd.read_csv(url)
print(sp500.shape)
print(sp500.head(3))
(503, 8)
  Symbol             Security  GICS Sector         GICS Sub-Industry  \
0    MMM                   3M  Industrials  Industrial Conglomerates   
1    AOS          A. O. Smith  Industrials         Building Products   
2    ABT  Abbott Laboratories  Health Care     Health Care Equipment   

     Headquarters Location  Date added    CIK Founded  
0    Saint Paul, Minnesota  1957-03-04  66740    1902  
1     Milwaukee, Wisconsin  2017-07-26  91142    1916  
2  North Chicago, Illinois  1957-03-04   1800    1888  
tickers = ['AAPL','MSFT','GOOGL','AMZN','TSLA']
prices = yf.download(tickers, period='1y', auto_adjust=True, progress=False)
prices = prices['Close'].reset_index()
prices.columns.name = None
print(prices.shape)
print(prices.head(3))
(251, 6)
        Date        AAPL        AMZN       GOOGL        MSFT        TSLA
0 2025-07-14  207.795624  225.690002  181.043518  499.033905  316.899994
1 2025-07-15  208.283691  226.350006  181.482269  501.811768  310.779999
2 2025-07-16  209.329559  223.190002  182.449509  501.613312  321.670013
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
tsla_df = ohlcv[ohlcv['Ticker'] == 'TSLA'].copy()
tsla_df['daily_return'] = tsla_df['Close'].pct_change() * 100
print(tsla_df[['Date','Close','daily_return']].head(7))
         Date       Close  daily_return
4  2025-07-14  316.899994           NaN
9  2025-07-15  310.779999     -1.931207
14 2025-07-16  321.670013      3.504091
19 2025-07-17  319.410004     -0.702586
24 2025-07-18  329.649994      3.205908
29 2025-07-21  328.489990     -0.351889
34 2025-07-22  332.109985      1.102011
aapl_returns = ohlcv[ohlcv['Ticker'] == 'AAPL'].copy()
msft_returns = ohlcv[ohlcv['Ticker'] == 'MSFT'].copy()
aapl_returns['cumulative_return'] = (1 + aapl_returns['Close'].pct_change()).cumprod() - 1
msft_returns['cumulative_return'] = (1 + msft_returns['Close'].pct_change()).cumprod() - 1
print(aapl_returns[['Date','cumulative_return']].tail(3))
print(msft_returns[['Date','cumulative_return']].tail(3))
           Date  cumulative_return
1240 2026-07-09           0.521784
1245 2026-07-10           0.517453
1250 2026-07-13           0.545653
           Date  cumulative_return
1243 2026-07-09          -0.229792
1248 2026-07-10          -0.228309
1253 2026-07-13          -0.227507
close_pivot = ohlcv.pivot(index='Date', columns='Ticker', values='Close')
print(close_pivot.shape)
print(close_pivot.head(3))
(251, 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.329559  223.190002  182.449509  501.613342  321.670013
fundamentals_tickers = ['AAPL','MSFT','GOOGL','AMZN','TSLA','NVDA','META','JPM','JNJ','XOM','WMT','V']
rows = []
for tk in fundamentals_tickers:
    info = yf.Ticker(tk).info
    rows.append({
        'ticker':       tk,
        'sector':       info.get('sector', 'Unknown'),
        'market_cap':   info.get('marketCap'),
        'pe_ratio':     info.get('trailingPE'),
        'eps':          info.get('trailingEps'),
        'profit_margin':info.get('profitMargins'),
        'debt_equity':  info.get('debtToEquity')
    })
fund_df = pd.DataFrame(rows)
print(fund_df.shape)
print(fund_df.head(3))
(12, 7)
  ticker                  sector     market_cap   pe_ratio    eps  \
0   AAPL              Technology  4719928410112  38.905567   8.26   
1   MSFT              Technology  2869567422464  23.007444  16.79   
2  GOOGL  Communication Services  4338868813824  27.122046  13.11   

   profit_margin  debt_equity  
0        0.27152       79.548  
1        0.39342       30.271  
2        0.37919       20.026  
sector_stats = fund_df.groupby('sector').agg({'market_cap':'mean','pe_ratio':'mean','profit_margin':'mean'}).round(2)
print(sector_stats)
                          market_cap  pe_ratio  profit_margin
sector                                                       
Communication Services  3.006822e+12     25.56           0.35
Consumer Cyclical       2.070567e+12    194.33           0.08
Consumer Defensive      9.150995e+11     40.49           0.03
Energy                  5.899089e+11     23.96           0.08
Financial Services      7.860991e+11     23.47           0.43
Healthcare              6.183731e+11     29.77           0.22
Technology              4.218204e+12     31.30           0.43
np.random.seed(42)
print('Random seed set to 42 for reproducibility')
Random seed set to 42 for reproducibility
portfolio_tickers = ['AAPL','MSFT','GOOGL','AMZN','TSLA','NVDA','META','NFLX','JPM','JNJ']
sector_map = {'AAPL':'Tech','MSFT':'Tech','GOOGL':'Tech','AMZN':'Consumer',
              'TSLA':'Auto','NVDA':'Tech','META':'Tech','NFLX':'Media',
              'JPM':'Finance','JNJ':'Health'}
prices = yf.download(portfolio_tickers, period='1y', auto_adjust=True, progress=False)['Close']
rows = []
for tk in portfolio_tickers:
    buy = round(float(prices[tk].iloc[0]), 2)
    cur = round(float(prices[tk].iloc[-1]), 2)
    shares = int(np.random.randint(5, 100))
    rows.append({'ticker': tk, 'shares': shares, 'buy_price': buy, 'cur_price': cur, 'sector': sector_map[tk]})
portfolio_df = pd.DataFrame(rows)
portfolio_df['gain_pct'] = np.round((portfolio_df['cur_price'] - portfolio_df['buy_price']) / portfolio_df['buy_price'] * 100, 2)
print(portfolio_df.shape)
print(portfolio_df.head(3))
(10, 6)
  ticker  shares  buy_price  cur_price sector  gain_pct
0   AAPL      56     207.80     320.12   Tech     54.05
1   MSFT      97     499.03     385.46   Tech    -22.76
2  GOOGL      19     181.04     355.02   Tech     96.10
sector_summary = portfolio_df.groupby('sector').agg({'gain_pct':'mean','shares':'sum'})
print(sector_summary)
          gain_pct  shares
sector                    
Auto        24.220      65
Consumer     9.140      76
Finance     17.960      79
Health      67.920      79
Media      -40.520      91
Tech        29.212     284
close_pivot['AAPL_return'] = close_pivot['AAPL'].pct_change()
close_pivot['AAPL_volatility'] = close_pivot['AAPL_return'].rolling(window=21).std() * np.sqrt(252)
close_pivot['AAPL_cum'] = (1 + close_pivot['AAPL_return']).cumprod()
cum_max = close_pivot['AAPL_cum'].cummax()
drawdown = close_pivot['AAPL_cum'] / cum_max - 1
max_drawdown = drawdown.min()
print(f"Annualized volatility: {close_pivot['AAPL_volatility'].iloc[-1]:.4f}")
print(f"Maximum drawdown: {max_drawdown:.2%}")
Annualized volatility: 0.3462
Maximum drawdown: -13.80%
aapl_data = yf.download('AAPL', period='1y', auto_adjust=True, progress=False)[['Close','Volume']].reset_index()
aapl_data.columns = ['date','close','volume']
aapl_data['sma20'] = aapl_data['close'].rolling(20).mean().round(2)
aapl_data['sma50'] = aapl_data['close'].rolling(50).mean().round(2)
aapl_data['signal'] = np.where(aapl_data['sma20'] > aapl_data['sma50'], 1, -1)
print(aapl_data.tail(3))
          date       close    volume   sma20   sma50  signal
248 2026-07-09  316.220001  48124500  296.92  296.83       1
249 2026-07-10  315.320007  34109200  298.10  297.73       1
250 2026-07-13  320.309998  11665158  299.34  298.73       1
nan_count = ohlcv.isna().sum().sum()
print(f'Total missing values in OHLCV data: {nan_count}')
ohlcv_clean = ohlcv.dropna()
print(f'Shape after dropping NaNs: {ohlcv_clean.shape}')
Total missing values in OHLCV data: 0
Shape after dropping NaNs: (1255, 7)
try:
    data = yf.download('ZZZZ_NOT_A_TICKER', period='1y', auto_adjust=True, progress=False)
    print('Data shape:', data.shape)
except Exception as e:
    print('Download failed:', e)
HTTP Error 404: {"quoteSummary":{"result":null,"error":{"code":"Not Found","description":"Quote not found for symbol: ZZZZ_NOT_A_TICKER"}}}

1 Failed download:
['ZZZZ_NOT_A_TICKER']: YFPricesMissingError('possibly delisted; no price data found  (period=1y) (Yahoo error = "No data found, symbol may be delisted")')
Data shape: (0, 6)
aapl_filtered = ohlcv[ohlcv['Ticker']=='AAPL'][['Date','Close']].reset_index(drop=True)
print(aapl_filtered.head(3))
        Date       Close
0 2025-07-14  207.795624
1 2025-07-15  208.283691
2 2025-07-16  209.329559
# Calculate 7-day rolling average closing price for TSLA
tsla_close = ohlcv[ohlcv['Ticker']=='TSLA'].copy()
tsla_close['rolling_avg'] = tsla_close['Close'].rolling(7).mean().round(2)
print(tsla_close[['Date', 'Close', 'rolling_avg']].tail(7))
           Date       Close  rolling_avg
1224 2026-07-02  393.450012       397.36
1229 2026-07-06  419.769989       403.68
1234 2026-07-07  402.899994       407.65
1239 2026-07-08  394.059998       409.70
1244 2026-07-09  406.549988       408.95
1249 2026-07-10  407.760010       407.11
1254 2026-07-13  394.894989       402.77
tech_syms = sp500[sp500['GICS Sector']=='Information Technology']['Symbol'].tolist()[:5]
tech_prices = yf.download(tech_syms, period='1y', auto_adjust=True, progress=False)['Close'].reset_index()
returns = tech_prices[tech_syms].pct_change().mean() * 100
summary = pd.DataFrame({'ticker': tech_syms, 'avg_daily_return_pct': returns.round(3).values})
print(summary)
  ticker  avg_daily_return_pct
0    ACN                -0.242
1   ADBE                -0.167
2    AMD                 0.618
3   AKAM                 0.258
4    APH                 0.222
summary.to_csv('tech_returns_summary.csv', index=False)
print('Results saved to tech_returns_summary.csv')
Results saved to tech_returns_summary.csv

Next steps: Keep learning and practicing!#

  • Practice these analytics examples with your favourite stocks.
  • Explore the yfinance and pandas documentation for deeper skills.
  • Watch our channel on YouTube for advanced finance Python projects!

Found this useful?

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