DEV Community

Cover image for Build Your Own Stock Data Downloader in Under 50 Lines of Python
Inder from lightspeedev
Inder from lightspeedev

Posted on

Build Your Own Stock Data Downloader in Under 50 Lines of Python

Fetch Stock Data the Clean Way (No More Eye Strain)

Before we jump into the code: If you need custom data tools or dashboards built, I’m currently open for freelance projects. Feel free to reach out to me on [LinkedIn Here].

We’ve all been there. You need historical price data for a specific stock to run some analysis. You go to Yahoo Finance, search for the ticker, navigate to the “Historical Data” tab, filter the dates, apply the filter, and then finally hunt for the download button and now its doesn’t work as well :> .

It’s tedious. Especially if you need to do it for five or ten different stocks.

I decided to solve this problem by building a dedicated tool. I wanted something clean, simple, and fast. The goal was to build a web app that takes a stock symbol and hands me a CSV file — no ads, no navigation menus, just data.

Thanks to Streamlit and yfinance, I managed to pull this off in under 50 lines of code.

Here is how I built it, and how you can run it too.

The Code

Here is the full script. It handles the UI, fetches the data from Yahoo Finance, handles errors (in case you mistype a symbol), and generates a download button.

import streamlit as st
import yfinance as yf

# Page Setup
st.set_page_config(page_title="Stock Downloader", layout="centered")
st.title(" Personal Stock Data Downloader")

# User Inputs should be exactly same as it would be on yahoo finance
ticker = st.text_input("Enter Stock Symbol", value="AAPL").upper()
mode = st.radio("Select Date Mode:", ["Period", "Date Range"], horizontal=True)

data = None 

try:
    # Logic to fetch data based on mode
    if mode == "Period":
        period = st.selectbox("Select Period", ["1mo", "3mo", "6mo", "1y", "5y", "max"])
        if st.button("Fetch Data"):
            data = yf.download(ticker, period=period, progress=False)

    elif mode == "Date Range":
        dates = st.date_input("Select Range", [])
        if len(dates) == 2 and st.button("Fetch Data"):
            data = yf.download(ticker, start=dates[0], end=dates[1], progress=False)

    # Display and Download Section
    if data is not None and not data.empty:
        st.success(f"Data fetched for {ticker}!")
        st.dataframe(data)
        csv = data.to_csv().encode('utf-8')
        st.download_button("Download CSV", csv, f"{ticker}_data.csv", "text/csv")
    elif data is not None and data.empty:
        st.error("No data found. Please check the ticker symbol.")

except Exception as e:
    st.error(f"An error occurred: {e}")
Enter fullscreen mode Exit fullscreen mode

How It Works

I wanted this to be robust, not just a script that works once and breaks the next time. Here is the logic behind the build:

  1. The Setup
    We import streamlit for the interface and yfinance to tap into market data. I used st.set_page_config to give the browser tab a proper title and center the layout—small details that make the app feel polished.

  2. Flexible Inputs
    Sometimes you want “the last 3 months” of data. Other times, you need a specific date range (e.g., from Jan 1st, 2020 to Jan 1st, 2021). I used a radio button to let the user switch between these two modes:

  • Period Mode: Uses a simple dropdown menu.
  • Date Range Mode: Uses a calendar picker. Note the check if len(dates) == 2. This ensures the code only runs once the user has picked both a start and an end date, preventing crashes.
  1. Error Handling (The “Pro” Touch)
    APIs can be finicky. Sometimes the internet cuts out, or more likely, you mistype “GOOG” as “GOOGGG.” I wrapped the logic in a try...except block and added a check for data.empty. Instead of the app crashing with a wall of red code, it simply tells the user: "No data found. Please check the ticker symbol."

  2. The Download Button
    This is the most important feature. Displaying data on a screen is nice, but useless if you can’t take it with you. The st.download_button converts our DataFrame into a CSV string and lets you save it directly to your machine.

Summary

This project proves you don’t need complex frameworks to build useful tools. In less than 50 lines, we have a functional, interactive web app that solves a real-world workflow problem.

If you’re looking to build something similar — maybe a dashboard that visualizes this data, or a portfolio tracker — I’m available for freelance work. [Reach out to me on LinkedIn] and let’s talk about your project.

Top comments (0)