Quant500 Academy

1. Where data comes from, and what free really costs

Level 1: Where they come from and what they carry inside

There is a question almost nobody asks before writing the first line of a strategy: who touched this number before it reached my hard drive. A price does not appear by spontaneous generation inside a CSV. It has passed through a chain of hands, and every hand charges something, filters something or delays something. Understanding that chain is what separates a backtest that means something from a backtest that only means you know how to use pandas.

The four links in the chain

Every hop adds latency, cost and one more opportunity to introduce an error. When two sources disagree, it is almost always because they have traveled different routes down this chain. It is also worth knowing which link you have plugged into: a vendor that consolidates on its own account from several direct feeds will not give you the same thing as one that resells the official consolidated tape, even if both sell you a column with the same name.

The license constrains you more than the price does

A beginner's mistake is to compare vendors by euros per month. What actually decides whether you can use a source is its terms:

What you pay when you do not pay

Free never means free: it means the payment is not in money. The bill arrives in five currencies:

The first thing any serious script should do is measure the real delay of its source instead of trusting the brochure:

import pandas as pd
import requests

# Placeholder: the key never goes hard-coded in the source or pushed to a repository.
CLAVE = "tu_clave_aqui"

def ultima_marca(simbolo):
    """Timestamp of the most recent candle the source admits to having."""
    r = requests.get(
        "https://api.proveedor-ejemplo.com/v1/intradia",
        params={"symbol": simbolo, "interval": "1min", "apikey": CLAVE},
        timeout=10,
    )
    r.raise_for_status()
    velas = pd.DataFrame(r.json()["values"])
    velas["datetime"] = pd.to_datetime(velas["datetime"], utc=True)
    return velas["datetime"].max()

ultima = ultima_marca("AAPL")
ahora = pd.Timestamp.utcnow()
print("Ultimo dato:", ultima)
print("Retraso aparente en minutos:", (ahora - ultima).total_seconds() / 60)

And the second is to audit the historical series before building anything on top of it. A gap of three consecutive sessions in the middle of a year is not a public holiday: it is an outage that nobody ever backfilled.

precios = pd.read_csv("aapl_gratis.csv", parse_dates=["date"], index_col="date").sort_index()

esperados = pd.bdate_range(precios.index.min(), precios.index.max())
faltan = esperados.difference(precios.index)

print("Sesiones esperadas:", len(esperados))
print("Sesiones recibidas:", len(precios))
print("Ausentes (incluye festivos):", len(faltan))

# Blocks of consecutive missing days: the long ones smell like an outage.
huecos = pd.Series(faltan)
bloques = (huecos.diff() != pd.Timedelta(days=1)).cumsum()
resumen = huecos.groupby(bloques).agg(["min", "max", "count"])
print(resumen[resumen["count"] >= 3])

A real case: the Tuesdays that broke thousands of scripts

In May 2017, Yahoo Finance withdrew without prior warning the historical CSV download endpoint that had been the community's de facto standard for a decade. Any project that depended on the Yahoo function in pandas-datareader stopped working overnight; the reaction was a swarm of unofficial reverse-engineered libraries, one of which ended up being yfinance.

Less than a year later, in April 2018, Quandl announced that its WIKI dataset of US daily equity prices would no longer be actively maintained. It was not deleted: it stayed there, frozen. That is the worse of the two failures, because it is silent: a script pointing at WIKI kept downloading, kept returning a DataFrame and kept producing a backtest that looked perfectly normal, except that it ran on data that no longer moved forward or got corrected.

Neither source breached anything: there was no contract to breach. That is exactly the currency in which free data is paid for. All this material is education, not financial advice.

The rest of Quant500

What you are learning, applied to the index every day:

The model portfolio, weekly in your inbox

Every Saturday, its week in one minute: how it went, the best and the worst, and which insiders bought with their own money. Plus, the day the model is rebuilt, which stocks come in and which go out. A simulation, not advice. At most one email a week, no ads, no account; one-click unsubscribe. Made by one person: Pol Gracia.

A model portfolio with simulated results, not a personalized recommendation. Your email is used for this only: privacy.

Behind the Academy and the rest of Quant500 there is one person: Pol Gracia Serrahima.