├── img ├── img ├── plot-1.png ├── plot-10.png ├── plot-11.png ├── plot-12.png ├── plot-13.png ├── plot-14.png ├── plot-15.png ├── plot-16.png ├── plot-17.png ├── plot-18.png ├── plot-19.png ├── plot-2.png ├── plot-20.png ├── plot-21.png ├── plot-22.png ├── plot-23.png ├── plot-24.png ├── plot-25.png ├── plot-26.png ├── plot-27.png ├── plot-28.png ├── plot-29.png ├── plot-3.png ├── plot-30.png ├── plot-31.png ├── plot-32.png ├── plot-33.png ├── plot-34.png ├── plot-35.png ├── plot-36.png ├── plot-37.png ├── plot-38.png ├── plot-39.png ├── plot-4.png ├── plot-40.png ├── plot-41.png ├── plot-42.png ├── plot-43.png ├── plot-5.png ├── plot-6.png ├── plot-7.png ├── plot-8.png └── plot-9.png ├── run_analysis.sh ├── Dockerfile ├── Makefile ├── .gitignore ├── LICENSE ├── report.tex ├── Stock_Market_Analysis.ipynb ├── README.md ├── Stock_Market_Analysis.R └── report.Rmd /img/img: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /img/plot-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-1.png -------------------------------------------------------------------------------- /img/plot-10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-10.png -------------------------------------------------------------------------------- /img/plot-11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-11.png -------------------------------------------------------------------------------- /img/plot-12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-12.png -------------------------------------------------------------------------------- /img/plot-13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-13.png -------------------------------------------------------------------------------- /img/plot-14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-14.png -------------------------------------------------------------------------------- /img/plot-15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-15.png -------------------------------------------------------------------------------- /img/plot-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-16.png -------------------------------------------------------------------------------- /img/plot-17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-17.png -------------------------------------------------------------------------------- /img/plot-18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-18.png -------------------------------------------------------------------------------- /img/plot-19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-19.png -------------------------------------------------------------------------------- /img/plot-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-2.png -------------------------------------------------------------------------------- /img/plot-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-20.png -------------------------------------------------------------------------------- /img/plot-21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-21.png -------------------------------------------------------------------------------- /img/plot-22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-22.png -------------------------------------------------------------------------------- /img/plot-23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-23.png -------------------------------------------------------------------------------- /img/plot-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-24.png -------------------------------------------------------------------------------- /img/plot-25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-25.png -------------------------------------------------------------------------------- /img/plot-26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-26.png -------------------------------------------------------------------------------- /img/plot-27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-27.png -------------------------------------------------------------------------------- /img/plot-28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-28.png -------------------------------------------------------------------------------- /img/plot-29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-29.png -------------------------------------------------------------------------------- /img/plot-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-3.png -------------------------------------------------------------------------------- /img/plot-30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-30.png -------------------------------------------------------------------------------- /img/plot-31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-31.png -------------------------------------------------------------------------------- /img/plot-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-32.png -------------------------------------------------------------------------------- /img/plot-33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-33.png -------------------------------------------------------------------------------- /img/plot-34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-34.png -------------------------------------------------------------------------------- /img/plot-35.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-35.png -------------------------------------------------------------------------------- /img/plot-36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-36.png -------------------------------------------------------------------------------- /img/plot-37.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-37.png -------------------------------------------------------------------------------- /img/plot-38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-38.png -------------------------------------------------------------------------------- /img/plot-39.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-39.png -------------------------------------------------------------------------------- /img/plot-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-4.png -------------------------------------------------------------------------------- /img/plot-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-40.png -------------------------------------------------------------------------------- /img/plot-41.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-41.png -------------------------------------------------------------------------------- /img/plot-42.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-42.png -------------------------------------------------------------------------------- /img/plot-43.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-43.png -------------------------------------------------------------------------------- /img/plot-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-5.png -------------------------------------------------------------------------------- /img/plot-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-6.png -------------------------------------------------------------------------------- /img/plot-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-7.png -------------------------------------------------------------------------------- /img/plot-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-8.png -------------------------------------------------------------------------------- /img/plot-9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Stock-Data-Analysis-R/HEAD/img/plot-9.png -------------------------------------------------------------------------------- /run_analysis.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # run_analysis.sh 3 | 4 | set -euo pipefail 5 | 6 | # Create image dir if missing 7 | mkdir -p img 8 | 9 | # Render HTML report 10 | Rscript -e "rmarkdown::render('Stock_Market_Analysis.Rmd')" 11 | 12 | # Optionally convert to PDF 13 | # pandoc Stock_Market_Analysis.html -o Stock_Market_Analysis.pdf --pdf-engine=xelatex 14 | 15 | echo "Analysis complete. See Stock_Market_Analysis.html and img/*.png" 16 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Dockerfile 2 | 3 | FROM rocker/tidyverse:latest 4 | 5 | # Install additional dependencies 6 | RUN install2.r --error \ 7 | quantmod \ 8 | PerformanceAnalytics \ 9 | zoo \ 10 | rmarkdown 11 | 12 | # Copy project files 13 | WORKDIR /home/project 14 | COPY . /home/project 15 | 16 | # Expose port if you want to serve (optional) 17 | # EXPOSE 8787 18 | 19 | # Default: run the analysis and exit 20 | CMD ["bash", "-lc", "Rscript -e \"rmarkdown::render('Stock_Market_Analysis.Rmd')\""] 21 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile 2 | 3 | RMD := Stock_Market_Analysis.Rmd 4 | HTML := $(RMD:.Rmd=.html) 5 | PDF := $(RMD:.Rmd=.pdf) 6 | IMG_DIR := img 7 | 8 | .PHONY: all clean docker 9 | 10 | all: $(HTML) 11 | 12 | $(HTML): $(RMD) 13 | Rscript -e "rmarkdown::render('$<', output_file='$@')" 14 | 15 | $(PDF): $(HTML) 16 | pandoc $< -o $@ --pdf-engine=xelatex 17 | 18 | clean: 19 | rm -f $(HTML) $(PDF) 20 | rm -rf $(IMG_DIR)/*.png 21 | 22 | docker: 23 | docker build -t stock-analysis:latest . 24 | 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # History files 2 | .Rhistory 3 | .Rapp.history 4 | 5 | # Session Data files 6 | .RData 7 | .RDataTmp 8 | 9 | # User-specific files 10 | .Ruserdata 11 | 12 | # Example code in package build process 13 | *-Ex.R 14 | 15 | # Output files from R CMD build 16 | /*.tar.gz 17 | 18 | # Output files from R CMD check 19 | /*.Rcheck/ 20 | 21 | # RStudio files 22 | .Rproj.user/ 23 | 24 | # produced vignettes 25 | vignettes/*.html 26 | vignettes/*.pdf 27 | 28 | # OAuth2 token, see https://github.com/hadley/httr/releases/tag/v0.3 29 | .httr-oauth 30 | 31 | # knitr and R markdown default cache directories 32 | *_cache/ 33 | /cache/ 34 | 35 | # Temporary files created by R markdown 36 | *.utf8.md 37 | *.knit.md 38 | 39 | # R Environment Variables 40 | .Renviron 41 | 42 | # pkgdown site 43 | docs/ 44 | 45 | # translation temp files 46 | po/*~ 47 | 48 | # RStudio Connect folder 49 | rsconnect/ 50 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Son (David) Nguyen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /report.tex: -------------------------------------------------------------------------------- 1 | \documentclass[11pt]{article} 2 | \usepackage[margin=1in]{geometry} 3 | \usepackage{graphicx} 4 | \usepackage{float} 5 | \usepackage{hyperref} 6 | \usepackage{caption} 7 | \title{Stock Market Analysis Report} 8 | \author{Your Name} 9 | \date{\today} 10 | 11 | \begin{document} 12 | \maketitle 13 | \tableofcontents 14 | \newpage 15 | 16 | \section{Introduction} 17 | This report summarizes the results of fetching, analyzing, and visualizing stock price data 18 | for several major tickers using R and the \texttt{quantmod} suite. 19 | 20 | \section{Methodology} 21 | \begin{itemize} 22 | \item Daily adjusted closing prices downloaded from Yahoo Finance. 23 | \item Computation of 20-day and 50-day Simple Moving Averages. 24 | \item Calculation of daily log returns and 20-day rolling volatility. 25 | \item Generation of per-ticker charts and a comparative normalized performance plot. 26 | \end{itemize} 27 | 28 | \section{Key Figures} 29 | 30 | \begin{figure}[H] 31 | \centering 32 | \includegraphics[width=\textwidth]{img/plot-01.png} 33 | \caption{AAPL Price with 20/50-day SMAs} 34 | \end{figure} 35 | 36 | \begin{figure}[H] 37 | \centering 38 | \includegraphics[width=\textwidth]{img/plot-03.png} 39 | \caption{AAPL Histogram of Daily Log Returns} 40 | \end{figure} 41 | 42 | \begin{figure}[H] 43 | \centering 44 | \includegraphics[width=\textwidth]{img/plot-15.png} 45 | \caption{GOOG 20-Day Rolling Volatility} 46 | \end{figure} 47 | 48 | \begin{figure}[H] 49 | \centering 50 | \includegraphics[width=\textwidth]{img/plot-43.png} 51 | \caption{Normalized Price Performance (Base = 100)} 52 | \end{figure} 53 | 54 | \section{Conclusions} 55 | Summarize trends, volatility patterns, and cross‐ticker comparisons here. 56 | 57 | \end{document} 58 | -------------------------------------------------------------------------------- /Stock_Market_Analysis.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "f9425d71", 6 | "metadata": {}, 7 | "source": [ 8 | "# Stock Market Analysis Notebook\n", 9 | "\n", 10 | "A Jupyter Notebook version of the Stock Market Analysis R script, implemented in Python using `yfinance`, `pandas`, and `matplotlib`." 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": null, 16 | "id": "ad17238e", 17 | "metadata": {}, 18 | "outputs": [], 19 | "source": [ 20 | "# Install required packages\n", 21 | "!pip install yfinance pandas matplotlib" 22 | ] 23 | }, 24 | { 25 | "cell_type": "code", 26 | "execution_count": null, 27 | "id": "d2705a90", 28 | "metadata": {}, 29 | "outputs": [], 30 | "source": [ 31 | "import yfinance as yf\n", 32 | "import pandas as pd\n", 33 | "import matplotlib.pyplot as plt\n", 34 | "from datetime import datetime\n", 35 | "\n", 36 | "# 1. Define tickers and date range\n", 37 | "tickers = ['AAPL','MSFT','GOOGL','AMZN','TSLA']\n", 38 | "start_date = '2020-01-01'\n", 39 | "end_date = datetime.today().strftime('%Y-%m-%d')\n", 40 | "\n", 41 | "# 2. Fetch data\n", 42 | "data = yf.download(tickers, start=start_date, end=end_date)['Adj Close']" 43 | ] 44 | }, 45 | { 46 | "cell_type": "code", 47 | "execution_count": null, 48 | "id": "03c776f1", 49 | "metadata": {}, 50 | "outputs": [], 51 | "source": [ 52 | "# 3. Calculate moving averages and returns\n", 53 | "ma20 = data.rolling(window=20).mean()\n", 54 | "ma50 = data.rolling(window=50).mean()\n", 55 | "returns = data.pct_change().apply(lambda x: np.log(1+x))\n", 56 | "volatility20 = returns.rolling(window=20).std() * (252**0.5)" 57 | ] 58 | }, 59 | { 60 | "cell_type": "code", 61 | "execution_count": null, 62 | "id": "e9f55cdd", 63 | "metadata": {}, 64 | "outputs": [], 65 | "source": [ 66 | "# 4. Plot Adjusted Close with SMAs\n", 67 | "plt.figure(figsize=(14,6))\n", 68 | "for ticker in tickers:\n", 69 | " plt.plot(data[ticker], label=f'{ticker} Price')\n", 70 | " plt.plot(ma20[ticker], label=f'{ticker} 20-day MA')\n", 71 | " plt.plot(ma50[ticker], label=f'{ticker} 50-day MA')\n", 72 | "plt.title('Adjusted Close Price with 20/50-day Moving Averages')\n", 73 | "plt.legend()\n", 74 | "plt.show()" 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": null, 80 | "id": "a2d6cb5c", 81 | "metadata": {}, 82 | "outputs": [], 83 | "source": [ 84 | "# 5. Plot Daily Returns Time Series\n", 85 | "plt.figure(figsize=(14,4))\n", 86 | "for ticker in tickers:\n", 87 | " plt.plot(returns[ticker], label=ticker)\n", 88 | "plt.title('Daily Log Returns')\n", 89 | "plt.legend()\n", 90 | "plt.show()" 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "execution_count": null, 96 | "id": "8de065f1", 97 | "metadata": {}, 98 | "outputs": [], 99 | "source": [ 100 | "# 6. Histogram of Returns for AAPL\n", 101 | "plt.figure(figsize=(8,4))\n", 102 | "plt.hist(returns['AAPL'].dropna(), bins=50, color='gray')\n", 103 | "plt.title('Histogram of AAPL Daily Log Returns')\n", 104 | "plt.xlabel('Log Return')\n", 105 | "plt.ylabel('Frequency')\n", 106 | "plt.show()" 107 | ] 108 | }, 109 | { 110 | "cell_type": "code", 111 | "execution_count": null, 112 | "id": "d4899e60", 113 | "metadata": {}, 114 | "outputs": [], 115 | "source": [ 116 | "# 7. Rolling Volatility\n", 117 | "plt.figure(figsize=(14,4))\n", 118 | "for ticker in tickers:\n", 119 | " plt.plot(volatility20[ticker], label=ticker)\n", 120 | "plt.title('20-Day Annualized Volatility')\n", 121 | "plt.legend()\n", 122 | "plt.show()" 123 | ] 124 | }, 125 | { 126 | "cell_type": "code", 127 | "execution_count": null, 128 | "id": "5c0b0c4a", 129 | "metadata": {}, 130 | "outputs": [], 131 | "source": [ 132 | "# 8. Cumulative Returns\n", 133 | "cum_ret = (1 + returns).cumprod() - 1\n", 134 | "plt.figure(figsize=(14,6))\n", 135 | "for ticker in tickers:\n", 136 | " plt.plot(cum_ret[ticker], label=ticker)\n", 137 | "plt.title('Cumulative Returns')\n", 138 | "plt.legend()\n", 139 | "plt.show()" 140 | ] 141 | } 142 | ], 143 | "metadata": {}, 144 | "nbformat": 4, 145 | "nbformat_minor": 5 146 | } 147 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Stock Market Data Analysis & Visualization 2 | 3 | A comprehensive R script that fetches daily adjusted closing prices for a selection of major tickers from Yahoo Finance and generates a suite of exploratory and analytical plots, including moving averages, returns, volatility, cumulative performance, and comparative normalized charts. 4 | 5 | > Author: [David Nguyen](https://github.com/hoangsonww) 6 | 7 | ## Table of Contents 8 | 9 | 1. [Project Overview](#project-overview) 10 | 2. [Features & Plots](#features--plots) 11 | 3. [Prerequisites](#prerequisites) 12 | 4. [Installation](#installation) 13 | 5. [Usage](#usage) 14 | 6. [Script Breakdown](#script-breakdown) 15 | 7. [Selected Visualizations](#selected-visualizations) 16 | 8. [Interpreting the Outputs](#interpreting-the-outputs) 17 | 9. [Extending & Customizing](#extending--customizing) 18 | 10. [Data Source & Citations](#data-source--citations) 19 | 11. [License](#license) 20 | 21 | --- 22 | 23 | ## Project Overview 24 | 25 | This repository provides a single R script (`Stock_Market_Analysis.R`) which: 26 | 27 | - **Automatically installs** required packages (`quantmod`, `PerformanceAnalytics`, `zoo`) if missing 28 | - **Downloads** daily adjusted closing prices for tickers (`AAPL`, `MSFT`, `GOOG`, `AMZN`, `TSLA`, `NFLX`, `NVDA`) 29 | - **Computes** 20-day & 50-day simple moving averages, daily log returns, 20-day rolling volatility, and monthly returns 30 | - **Renders** 43 separate plots, each saved as `plot-.png` in the working directory 31 | - **Performs** a final comparative normalized performance chart (base = 100) 32 | 33 | --- 34 | 35 | ## Features & Plots 36 | 37 | 1. **Price Chart with SMAs** 38 | 2. **Daily Log Returns Time Series** 39 | 3. **Histogram of Daily Returns** 40 | 4. **20-Day Rolling Volatility** 41 | 5. **Cumulative Returns** 42 | 6. **Monthly Returns Boxplot** 43 | 7. **Comparative Normalized Performance** 44 | 45 | Each ticker produces six individual plots, plus one comparative chart, for a total of **43** PNG files. 46 | 47 | --- 48 | 49 | ## Prerequisites 50 | 51 | - **R** (version ≥ 4.0) 52 | - Internet connection to fetch data from Yahoo Finance 53 | 54 | --- 55 | 56 | ## Installation 57 | 58 | 1. **Clone** this repository: 59 | ```bash 60 | git clone https://github.com/yourusername/stock-market-analysis.git 61 | cd stock-market-analysis 62 | ``` 63 | 64 | 2. **Open** R or RStudio in this folder. 65 | 66 | --- 67 | 68 | ## Usage 69 | 70 | In an R console or RStudio: 71 | 72 | ```r 73 | # Source the analysis script 74 | source("Stock_Market_Analysis.R") 75 | ``` 76 | 77 | The script will: 78 | 79 | 1. Install any missing packages. 80 | 2. Download and process each ticker’s data. 81 | 3. Display each plot interactively (with a white background). 82 | 4. Save each plot as `plot-1.png` … `plot-43.png` in the project directory. 83 | 5. Print summary statistics for each ticker’s returns. 84 | 85 | --- 86 | 87 | ## Script Breakdown 88 | 89 | 1. **Setup** 90 | 91 | * Defines and installs package list 92 | * Loads libraries 93 | 94 | 2. **Data Fetch & Preparation** 95 | 96 | * Defines tickers & date range 97 | * Downloads via `quantmod::getSymbols()` 98 | * Extracts adjusted close, SMAs, returns, volatility, monthly returns 99 | 100 | 3. **Plotting Sections (per ticker)** 101 | 102 | * **Price + SMAs** 103 | * **Daily Returns** 104 | * **Histogram of Returns** 105 | * **Rolling Volatility** 106 | * **Cumulative Returns** 107 | * **Monthly Returns Boxplot** 108 | 109 | 4. **Comparative Performance** 110 | 111 | * Merges all adjusted series 112 | * Normalizes each to 100 at the first date 113 | * Plots on a single chart with legend 114 | 115 | 5. **Summary Statistics** 116 | 117 | * Prints mean, SD, skewness, kurtosis, etc., via `PerformanceAnalytics::table.Stats()` 118 | 119 | --- 120 | 121 | ## Selected Visualizations 122 | 123 | Below are some of the 43 plots generated to visualize the stock market data better: 124 | 125 | ### Apple Stock (AAPL) 126 | 127 |

128 | 129 |

130 |

131 | 132 |

133 |

134 | 135 |

136 |

137 | 138 |

139 |

140 | 141 |

142 |

143 | 144 |

145 | 146 | ### Microsoft Stock (MSFT) 147 | 148 |

149 | 150 |

151 |

152 | 153 |

154 |

155 | 156 |

157 |

158 | 159 |

160 |

161 | 162 |

163 |

164 | 165 |

166 | 167 | --- 168 | 169 | ## Interpreting the Outputs 170 | 171 | * **SMAs vs. Price:** Identify trends and potential crossovers 172 | * **Returns Series & Histogram:** Assess volatility clustering & distribution shape 173 | * **Rolling Volatility:** Track risk over time (annualized) 174 | * **Cumulative Returns:** Evaluate total growth from start date 175 | * **Monthly Boxplot:** Compare variability across months 176 | * **Normalized Chart:** Compare relative performance on a common scale 177 | 178 | --- 179 | 180 | ## Extending & Customizing 181 | 182 | * **Add tickers:** Update `tickers <- c(...)` 183 | * **Change SMAs:** Modify `n` in `SMA()` calls 184 | * **Alternative returns:** Use `type = "arithmetic"` in `dailyReturn()` 185 | * **Additional analytics:** Compute drawdowns, Sharpe ratios via `PerformanceAnalytics` 186 | * **Export formats:** Switch `png()` to `pdf()` or `svg()` 187 | 188 | --- 189 | 190 | ## Data Source & Citations 191 | 192 | * **Yahoo Finance** (via `quantmod::getSymbols`) 193 | * **R & Packages:** 194 | 195 | * R Core Team (2023). R: A language and environment for statistical computing. 196 | * Jeffrey Ryan and Jim Lemon et al., *quantmod* package. 197 | * Brian Peterson, *PerformanceAnalytics* package. 198 | 199 | --- 200 | 201 | ## License 202 | 203 | Distributed under the MIT License. See [LICENSE](LICENSE) for details. 204 | -------------------------------------------------------------------------------- /Stock_Market_Analysis.R: -------------------------------------------------------------------------------- 1 | # ================================================================================= 2 | # Stock_Market_Analysis.R 3 | # 4 | # A comprehensive R script to fetch, analyze, and visualize stock price data 5 | # for multiple tickers using quantmod & PerformanceAnalytics. 6 | # 7 | # Features: 8 | # 1. Downloads daily adjusted closing prices for a set of tickers from Yahoo Finance. 9 | # 2. Calculates 20-day & 50-day SMAs. 10 | # 3. Computes daily log returns & 20-day rolling volatility. 11 | # 4. Generates for each ticker: 12 | # • Price chart with SMAs 13 | # • Daily returns time series 14 | # • Histogram of returns 15 | # • Rolling volatility chart 16 | # • Cumulative returns chart 17 | # • Boxplot of monthly returns 18 | # 5. Comparative normalized performance chart. 19 | # 6. Saves each plot as plot-1.png through plot-43.png 20 | # 21 | # Dependencies: 22 | # - quantmod 23 | # - PerformanceAnalytics 24 | # - zoo 25 | # 26 | # Usage: 27 | # 1. Ensure R ≥ 4.0 is installed. 28 | # 2. source("Stock_Market_Analysis.R") 29 | # ================================================================================= 30 | 31 | # 0. Install & load required packages 32 | pkgs <- c("quantmod", "PerformanceAnalytics", "zoo") 33 | for(pkg in pkgs) { 34 | if (!requireNamespace(pkg, quietly = TRUE)) install.packages(pkg) 35 | library(pkg, character.only = TRUE) 36 | } 37 | 38 | # 1. Define tickers and date range 39 | tickers <- c("AAPL","MSFT","GOOG","AMZN","TSLA","NFLX","NVDA") 40 | start_date <- as.Date("2020-01-01") 41 | end_date <- Sys.Date() 42 | 43 | # 2. Fetch data 44 | getSymbols(tickers, src = "yahoo", 45 | from = start_date, to = end_date, 46 | auto.assign = TRUE) 47 | 48 | # 3. Processing function 49 | process_symbol <- function(sym) { 50 | adj <- Ad(get(sym)) # Adjusted close price 51 | sma20 <- SMA(adj, n = 20) # 20-day SMA 52 | sma50 <- SMA(adj, n = 50) # 50-day SMA 53 | ret <- dailyReturn(adj, type = "log") # Daily log returns 54 | vol20 <- runSD(ret, n = 20) * sqrt(252) # 20-day rolling volatility (annualized) 55 | mo_ret <- monthlyReturn(adj, type = "log") # Monthly log returns 56 | 57 | list( 58 | adj = adj, 59 | sma20 = sma20, 60 | sma50 = sma50, 61 | ret = ret, 62 | vol20 = vol20, 63 | mo_ret = mo_ret 64 | ) 65 | } 66 | 67 | # 4. Process all tickers 68 | stock_data <- setNames(lapply(tickers, process_symbol), tickers) 69 | 70 | # 5. Per‐ticker analyses (6 plots per ticker) 71 | plot_counter <- 1 72 | 73 | for(sym in tickers) { 74 | data <- stock_data[[sym]] 75 | 76 | # 5.1 Price chart with SMAs 77 | png(sprintf("plot-%d.png", plot_counter), width=800, height=600) 78 | par(bg="white") 79 | chartSeries(get(sym), 80 | name = paste(sym, "Price + SMAs"), 81 | TA = NULL, 82 | theme = chartTheme("white")) 83 | addTA(data$sma20, on = 1, col = "blue", lwd = 1.5) 84 | addTA(data$sma50, on = 1, col = "red", lwd = 1.5) 85 | dev.off() 86 | plot_counter <- plot_counter + 1 87 | 88 | # 5.2 Daily returns time series 89 | png(sprintf("plot-%d.png", plot_counter), width=800, height=600) 90 | par(bg="white") 91 | chartSeries(data$ret, 92 | name = paste(sym, "Daily Log Returns"), 93 | TA = NULL, 94 | theme = chartTheme("white")) 95 | dev.off() 96 | plot_counter <- plot_counter + 1 97 | 98 | # 5.3 Histogram of daily returns 99 | png(sprintf("plot-%d.png", plot_counter), width=800, height=600) 100 | par(bg="white") 101 | hist(as.numeric(data$ret), 102 | breaks = 50, 103 | main = paste(sym, "Histogram of Daily Returns"), 104 | xlab = "Daily Log Return", 105 | col = "lightgray", 106 | border = "white") 107 | dev.off() 108 | plot_counter <- plot_counter + 1 109 | 110 | # 5.4 Rolling volatility 111 | png(sprintf("plot-%d.png", plot_counter), width=800, height=600) 112 | par(bg="white") 113 | chartSeries(data$vol20, 114 | name = paste(sym, "20-Day Rolling Volatility"), 115 | TA = NULL, 116 | theme = chartTheme("white")) 117 | dev.off() 118 | plot_counter <- plot_counter + 1 119 | 120 | # 5.5 Cumulative returns 121 | cum_ret <- cumprod(1 + data$ret) - 1 122 | png(sprintf("plot-%d.png", plot_counter), width=800, height=600) 123 | par(bg="white") 124 | chartSeries(cum_ret, 125 | name = paste(sym, "Cumulative Returns"), 126 | TA = NULL, 127 | theme = chartTheme("white")) 128 | dev.off() 129 | plot_counter <- plot_counter + 1 130 | 131 | # 5.6 Monthly return boxplot 132 | png(sprintf("plot-%d.png", plot_counter), width=800, height=600) 133 | par(bg="white") 134 | boxplot(as.numeric(data$mo_ret), 135 | main = paste(sym, "Monthly Log Returns"), 136 | ylab = "Log Return", 137 | col = "skyblue", 138 | border = "darkblue") 139 | dev.off() 140 | plot_counter <- plot_counter + 1 141 | } 142 | 143 | # 6. Comparative normalized performance (1 plot) 144 | # Merge all adjusted series into one xts object 145 | adj_all <- do.call(merge, lapply(stock_data, `[[`, "adj")) 146 | colnames(adj_all) <- tickers 147 | 148 | # Normalize so each series starts at 100 149 | norm_prices <- sweep(adj_all, 2, 150 | as.numeric(adj_all[1, , drop = TRUE]), 151 | FUN = "/") * 100 152 | 153 | png(sprintf("plot-%d.png", plot_counter), width=800, height=600) 154 | par(bg="white") 155 | plot.zoo(norm_prices, 156 | screens = 1, 157 | col = rainbow(length(tickers)), 158 | lwd = 2, 159 | main = "Normalized Price Performance (Base = 100)", 160 | xlab = "Date", 161 | ylab = "Normalized Price") 162 | legend("topleft", 163 | legend = tickers, 164 | col = rainbow(length(tickers)), 165 | lwd = 2, 166 | bty = "n") 167 | dev.off() 168 | plot_counter <- plot_counter + 1 169 | 170 | # 7. Print summary statistics for each ticker’s returns 171 | for(sym in tickers) { 172 | cat("\n=== Summary stats for", sym, "===\n") 173 | print(table.Stats(stock_data[[sym]]$ret)) 174 | } 175 | 176 | # ================================================================================= 177 | # End of Stock_Market_Analysis.R 178 | # ================================================================================= 179 | # Note: Ensure to run this script in a directory where you have write permissions 180 | -------------------------------------------------------------------------------- /report.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Stock Market Analysis & Visualization" 3 | author: "David Nguyen" 4 | date: "`r Sys.Date()`" 5 | output: 6 | html_document: 7 | toc: true 8 | toc_depth: 3 9 | theme: united 10 | code_folding: hide 11 | --- 12 | 13 | ```{r setup, include=FALSE} 14 | knitr::opts_chunk$set( 15 | echo = TRUE, 16 | warning = FALSE, 17 | message = FALSE, 18 | fig.align = "center", 19 | fig.width = 10, 20 | fig.height = 6 21 | ) 22 | ```` 23 | 24 | # Project Overview 25 | 26 | This analysis fetches daily adjusted closing prices for a set of major tickers from Yahoo Finance, computes moving averages, returns, volatility, and generates a suite of plots. All figures are rendered inline and also saved as PNG files. 27 | 28 | # Dependencies 29 | 30 | ```{r libs} 31 | pkgs <- c("quantmod", "PerformanceAnalytics", "zoo") 32 | for(pkg in pkgs) { 33 | if (!requireNamespace(pkg, quietly = TRUE)) install.packages(pkg) 34 | library(pkg, character.only = TRUE) 35 | } 36 | ``` 37 | 38 | # 1. Parameters 39 | 40 | ```{r params} 41 | tickers <- c("AAPL","MSFT","GOOG","AMZN","TSLA","NFLX","NVDA") 42 | start_date <- as.Date("2020-01-01") 43 | end_date <- Sys.Date() 44 | img_dir <- "img" 45 | dir.create(img_dir, showWarnings = FALSE) 46 | ``` 47 | 48 | # 2. Data Retrieval & Processing 49 | 50 | ```{r fetch} 51 | getSymbols(tickers, src = "yahoo", 52 | from = start_date, to = end_date, 53 | auto.assign = TRUE) 54 | ``` 55 | 56 | Define a helper to save each plot with incrementing index: 57 | 58 | ```{r saver} 59 | plot_index <- 1 60 | save_plot <- function(fig) { 61 | file <- file.path(img_dir, sprintf("plot-%02d.png", plot_index)) 62 | ggplot2::ggsave(file, fig, width = 10, height = 6, bg = "white") 63 | assign("plot_index", plot_index + 1, envir = .GlobalEnv) 64 | } 65 | ``` 66 | 67 | Processing function: 68 | 69 | ```{r process} 70 | process_symbol <- function(sym) { 71 | adj <- Ad(get(sym)) 72 | sma20 <- SMA(adj, n = 20) 73 | sma50 <- SMA(adj, n = 50) 74 | ret <- dailyReturn(adj, type = "log") 75 | vol20 <- runSD(ret, n = 20) * sqrt(252) 76 | mo_ret <- monthlyReturn(adj, type = "log") 77 | list(adj = adj, sma20 = sma20, sma50 = sma50, 78 | ret = ret, vol20 = vol20, mo_ret = mo_ret) 79 | } 80 | stock_data <- setNames(lapply(tickers, process_symbol), tickers) 81 | ``` 82 | 83 | # 3. Per–Ticker Visualizations 84 | 85 | We iterate through each ticker and produce six figures: 86 | 87 | ```{r per-ticker, results='hide'} 88 | library(ggplot2) 89 | for(sym in tickers) { 90 | d <- stock_data[[sym]] 91 | 92 | ## 3.1 Price + SMAs 93 | p1 <- chartSeries(get(sym), 94 | name = paste(sym, "Price + SMAs"), 95 | TA = NULL, 96 | theme = chartTheme("white")) 97 | addTA(d$sma20, on = 1, col = "blue", lwd = 1.5) 98 | addTA(d$sma50, on = 1, col = "red", lwd = 1.5) 99 | 100 | ## save via quantmod → grab last plot 101 | dev.copy(png, filename = file.path(img_dir, sprintf("plot-%02d.png", plot_index)), 102 | width=800, height=480) 103 | dev.off() 104 | plot_index <<- plot_index + 1 105 | 106 | ## 3.2 Daily Returns 107 | p2 <- chartSeries(d$ret, 108 | name = paste(sym, "Daily Log Returns"), 109 | TA = NULL, 110 | theme = chartTheme("white")) 111 | dev.copy(png, file.path(img_dir, sprintf("plot-%02d.png", plot_index)), width=800, height=480); dev.off() 112 | plot_index <<- plot_index + 1 113 | 114 | ## 3.3 Histogram of Returns 115 | p3 <- ggplot(data.frame(ret = coredata(d$ret)), aes(ret)) + 116 | geom_histogram(bins = 50, fill="lightgray", color="white") + 117 | labs(title = paste(sym, "Histogram of Daily Returns"), 118 | x = "Daily Log Return", y = "Frequency") + 119 | theme_minimal() 120 | print(p3); save_plot(p3) 121 | 122 | ## 3.4 Rolling Volatility 123 | p4 <- chartSeries(d$vol20, 124 | name = paste(sym, "20-Day Rolling Volatility"), 125 | TA = NULL, 126 | theme = chartTheme("white")) 127 | dev.copy(png, file.path(img_dir, sprintf("plot-%02d.png", plot_index)), width=800, height=480); dev.off() 128 | plot_index <<- plot_index + 1 129 | 130 | ## 3.5 Cumulative Returns 131 | cum_ret <- cumprod(1 + d$ret) - 1 132 | p5 <- chartSeries(cum_ret, 133 | name = paste(sym, "Cumulative Returns"), 134 | TA = NULL, 135 | theme = chartTheme("white")) 136 | dev.copy(png, file.path(img_dir, sprintf("plot-%02d.png", plot_index)), width=800, height=480); dev.off() 137 | plot_index <<- plot_index + 1 138 | 139 | ## 3.6 Monthly Return Boxplot 140 | df_mo <- data.frame(mo = coredata(d$mo_ret)) 141 | p6 <- ggplot(df_mo, aes(factor(format(index(d$mo_ret), "%Y-%m")), mo)) + 142 | geom_boxplot(fill="skyblue", color="darkblue") + 143 | labs(title = paste(sym, "Monthly Log Returns"), 144 | x = "Month", y = "Log Return") + 145 | theme_minimal() + 146 | theme(axis.text.x = element_text(angle=90, vjust=0.5)) 147 | print(p6); save_plot(p6) 148 | } 149 | ``` 150 | 151 | # 4. Comparative Normalized Performance 152 | 153 | ```{r comparative} 154 | # merge adjusted closes 155 | adj_all <- do.call(merge, lapply(stock_data, `[[`, "adj")) 156 | colnames(adj_all) <- tickers 157 | norm_prices <- sweep(adj_all, 2, as.numeric(adj_all[1,]), FUN="/") * 100 158 | 159 | # plot.TimeSeries from PerformanceAnalytics 160 | chart.TimeSeries(norm_prices, 161 | main = "Normalized Price Performance (Base = 100)", 162 | legend.loc = "topleft", 163 | col = rainbow(length(tickers)), 164 | lwd = 2, 165 | SSL = FALSE, 166 | grid.col = "white", 167 | legend.names = tickers) 168 | dev.copy(png, file.path(img_dir, sprintf("plot-%02d.png", plot_index)), width=800, height=480); dev.off() 169 | plot_index <<- plot_index + 1 170 | ``` 171 | 172 | # 5. Summary Statistics 173 | 174 | ```{r stats} 175 | for(sym in tickers) { 176 | cat("\n##", sym, "\n") 177 | print(table.Stats(stock_data[[sym]]$ret)) 178 | } 179 | ``` 180 | 181 | # Selected Figures 182 | 183 |

184 | 185 |

186 |

187 | 188 |

189 |

190 | 191 |

192 |

193 | 194 |

195 | 196 | # Interpretation & Next Steps 197 | 198 | * **Moving Averages** highlight trend shifts. 199 | * **Returns & Volatility** reveal risk patterns. 200 | * **Cumulative & Normalized** charts facilitate cross‐ticker comparison. 201 | * Extend by adding indicators (RSI, MACD), alternative timeframes, or portfolio simulations. 202 | --------------------------------------------------------------------------------