1. Downloading historical prices with yfinance
Level 3: Market Data and APIs
Every strategy, however sophisticated, starts with a table of prices. The most widely used library for getting that table for free, with no account and no API key required, is yfinance, which downloads historical and real-time data straight from Yahoo Finance.
import yfinance as yf
import datetime as dt
start = dt.datetime(2018, 1, 1)
end = dt.datetime.now()
data = yf.download("TSLA", start, end, auto_adjust=False) # auto_adjust=False is needed for the Adj Close column to exist
data.head()The result is a pandas DataFrame — the table structure you will be using constantly from now on — with one row per trading day and columns such as Open, High, Low, Close, Adj Close and Volume. Adj Close is the closing price adjusted for dividends and splits: it is the one you should use almost always to compute returns, because the plain Close can show false jumps every time a company pays a dividend or splits its shares.
Once downloaded, it is good practice to save the data to a local file, so you do not have to download it again every time you run the script — and so you can work offline, or if the source stops being available.
data.to_csv("TSLA.csv")
# later on, to load it again without downloading afresh:
import pandas as pd
saved_data = pd.read_csv("TSLA.csv", parse_dates=True, index_col=0)parse_dates=True tells pandas to interpret the first column as dates, not as text — without this, any calculation that depends on the chronological order of the data would give incorrect results.
With the data already in a DataFrame, producing a first chart is a single line:
import matplotlib.pyplot as plt
data["Adj Close"].plot()
plt.show()It is the fastest way to check, just by looking, whether the downloaded data makes sense — odd gaps, prices that spike for no reason, or an incomplete date range are errors your eyes catch far faster than reading numbers.