Skip to content

Repository files navigation

AAPL Stock Analysis 2021-2026— Python & Pandas

End-to-end time-series analysis and feature engineering on Apple Inc. (NASDAQ: AAPL) historical price data covering 5 years of market activity (2021–2026), built entirely in Python using pandas, numpy, and matplotlib.


Project Overview

Ticker AAPL (Apple Inc.)
Data Period July 2021 – July 2026
Trading Days 1,255
Starting Price $141.96
Latest Price $316.15
Cumulative Return +122.7%
Max Drawdown -33.4% (2022 bear market)
Sharpe Ratio 0.72
Tools Python · pandas · numpy · matplotlib

Project Structure

AAPL-Stock-Analysis/
├── AAPL.csv                        # Raw price data (OHLCV)
├── AAPL_transformed.csv            # Cleaned dataset with all features
├── AAPL_monthly_summary.csv        # Monthly aggregation table
├── AAPL_quarterly_summary.csv      # Quarterly aggregation table
├── AAPL_yearly_summary.csv         # Yearly aggregation table
├── AAPL_pivot_close.csv            # Avg close pivot (Year x Quarter)
├── AAPL_pivot_volume.csv           # Total volume pivot (Year x Quarter)
├── AAPL_long_format.csv            # OHLC in long/melted format
├── AAPL_Report.pdf                 # Full analysis report (4 pages)
└── README.md                       # This file

Analysis Steps

Step 1 — Load & Inspect

Profiled the raw CSV structure, identified 2 junk metadata header rows, confirmed all columns stored as object/str type.

Step 2 — Data Cleaning

df = df_raw.iloc[2:].copy()                        # skip junk rows
df.columns = ["Date","Close","High","Low","Open","Volume"]
df["Date"]   = pd.to_datetime(df["Date"])           # fix types
df["Close"]  = df["Close"].astype(float)
df["Volume"] = df["Volume"].astype(int)
df = df.sort_values("Date").reset_index(drop=True)  # sort oldest → newest

Step 3 — Missing Values

Dropped nulls on critical price columns — 0 rows removed after removing junk header rows.

Step 4 — Time Features

df["Year"]       = df["Date"].dt.year
df["Month_Name"] = df["Date"].dt.strftime("%b")
df["Quarter"]    = df["Date"].dt.quarter
df["Weekday"]    = df["Date"].dt.day_name()
df["Is_Month_End"]   = df["Date"].dt.is_month_end
df["Is_Quarter_End"] = df["Date"].dt.is_quarter_end

Step 5 — Feature Engineering

18+ new analytical columns across 6 categories:

Category Features
Price Daily_Range, Daily_Price_Change, Open_to_Close_Change, Overnight_Gap
Returns Daily_Return_%, Open_to_Close_%, Rolling_Monthly_Return_%
Moving Averages SMA_7/21/50/200, EMA_7/21/50/200, EMA_SMA_Diff, Dist_from_SMA200_%
Volatility Volatility_7/21/30d, Ann_Volatility_30d, ATR_14/30, BB_Upper/Mid/Lower/Width
Momentum RSI_14/7, MACD, MACD_Signal, MACD_Hist, ROC_5/10/20
Volume Vol_SMA_20, Volume_Ratio, OBV, Volume_Spike

Step 6 — Filtering & Sorting

# Top 10 highest close days
df.sort_values("Close", ascending=False).head(10)

# High volume bullish sessions
df[(df["High_Volume"] == True) & (df["Direction"] == "UP")]

# Days above 30-day moving average
df[df["Close"] > df["MA_30"]]

Step 7 — Grouping & Aggregation

# Yearly summary
df.groupby("Year").agg(
    Avg_Close    = ("Close", "mean"),
    Max_Close    = ("Close", "max"),
    UP_Days      = ("Direction", lambda x: (x == "UP").sum()),
    Volatility   = ("Daily_Return_%", "std")
)

# Monthly summary
df.groupby(["Year","Month","Month_Name"]).agg(
    Open_Price   = ("Open",  "first"),
    Close_Price  = ("Close", "last"),
    Total_Volume = ("Volume","sum"),
    Trading_Days = ("Date",  "count")
)

Step 8 — Risk Metrics

sharpe  = (returns.mean() / returns.std()) * np.sqrt(252)      # 0.72
sortino = (returns.mean() / downside_std)  * np.sqrt(252)
var_95  = np.percentile(returns, 5)                             # -2.72%
max_dd  = df["Drawdown_%"].min()                                # -33.4%

Step 9 — Data Formatting & Restructuring

# Pivot table — avg close by year and quarter
df.pivot_table(values="Close", index="Year",
               columns="Quarter", aggfunc="mean")

# Melt OHLC to long format
df[["Date","Open","High","Low","Close"]].melt(
    id_vars="Date", value_vars=["Open","High","Low","Close"],
    var_name="Price_Type", value_name="Price"
)

Key Findings

Trends

  • AAPL delivered +122.7% cumulative return from Jul 2021 to Jul 2026
  • 2022 bear market caused a -33.4% max drawdown with volatility spiking above 40% annualized
  • Strong 2023–2024 recovery — best annual return year was 2023; MACD turned bullish in early 2023 and stayed positive
  • Q4 seasonality is consistent — November is the strongest calendar month every year; September is the weakest
  • Volume trended down year-over-year, suggesting institutional accumulation over retail speculation

Key Insights

  • Sharpe Ratio of 0.72 — decent but not exceptional risk-adjusted return; the 2022 drawdown weighs on this
  • VaR (95%) of -2.72% — on 1 in 20 trading days, losses can exceed this level
  • RSI below 30 in 2022 closely coincided with major price bottoms and subsequent rallies
  • OBV trended upward throughout — buying pressure outweighed selling even during dips
  • Bollinger Band Width compressed significantly in 2025–2026, preceding the breakout to ATH of $316.22

Recommendations

  • Use SMA 200 as a directional filter — hold when above, reduce exposure when below
  • Buy September dips — historically the weakest month, consistently followed by Q4 strength
  • Use RSI < 35 + MACD crossover as a combined entry signal
  • Size positions using 1.5–2× ATR_14 as stop-loss distance (~$4.50–$7.50)
  • Increase allocation heading into October–November each year; reduce after December peak

Visualizations

Chart Description
Price + SMA 50/200 Full 5-year price history with moving averages and bull/bear shading
Volume Trend Daily volume with 20-day moving average (green=UP, red=DOWN days)
Monthly Returns Bar chart of every month's return + seasonality average by calendar month
MACD + Volatility MACD indicator with signal line and 30-day annualized volatility
Bollinger Bands Dynamic support/resistance bands around 20-day SMA
RSI 14-day RSI with overbought (70) and oversold (30) zones
Cumulative vs Drawdown Total return vs peak-to-trough drawdown on dual axis
Annual Returns Year-by-year return bar chart

Requirements

pip install pandas numpy matplotlib
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

Disclaimer

This project is for educational purposes only and does not constitute financial advice. Past performance is not indicative of future results.


Analysis by Jonas Nwachukwu · AAPL Stock Analysis 2021–2026

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages