Rotate to portrait

Vizual Stocks works best vertically on mobile.

VizualStocks API

PYTHON TUTORIAL · CONSENSUS RESEARCH

Track revenue and EPS estimate revisions with Python

Follow changes in expectations—not just the latest estimate. Use Python to download consensus revenue and normalized EPS history for a selected reporting period, calculate revisions and export a CSV and chart.

01 · SETUP

Install the libraries and set your API key

You’ll need Python 3.10 or newer. Save estimate_revisions.py in your working folder, then install the libraries:

Terminal · install dependencies
python -m pip install requests pandas matplotlib

Log in to get your API key. In the dashboard, click Create API key → Create key → Copy, then return here and replace YOUR_API_KEY below.

Windows PowerShell
$env:VIZUALSTOCKS_API_KEY = "YOUR_API_KEY"
macOS / Linux shell
export VIZUALSTOCKS_API_KEY="YOUR_API_KEY"

Choose the command for your terminal. The key is sent in the X-API-Key header and is not saved in your research export.

02 · PERIODS

Find the reporting periods with estimate history

Terminal · list target periods
python estimate_revisions.py --ticker PLTR --list-periods

The Estimate Revision Trends endpoint groups observations by frequency and target normalizedPeriod. Discovery requests one latest observation per target period to keep the response small; the export below requests the full available history for your selection.

Choose one label returned by discovery. This tutorial uses Q3'26 as a fixed example, not a rolling “next quarter.” It is the API’s normalized chart label, not a promise of a particular issuer fiscal-quarter identity.

03 · EXPORT

Track revenue and EPS estimates for one quarter

Terminal · export quarterly estimate revisions
python estimate_revisions.py --ticker PLTR --period "Q3'26" --output-dir pltr-q3-26-estimates

The new folder contains estimate-revisions.csv, estimate-revisions.png and retrieval notes. The top panel charts consensus revenue in millions of the returned currency; the bottom panel charts normalized EPS in currency per share. The CSV retains unscaled API values.

The horizontal axis is collectedDate: when that observation was collected. Every point in both panels forecasts the same target period. A line that instead connects next-quarter estimates to next-year estimates would mix economic growth with revisions and answer a different question.

One observation can show an estimate level, but it cannot establish a revision. The first row’s change fields stay blank.

04 · PANDAS

Calculate changes without mixing periods or filling gaps

Keep the downloaded script beside your notebook and run the same request:

Python · inspect estimate changes
from estimate_revisions import make_session, api_get, revision_frame

with make_session() as session:
    payload = api_get(
        session, "/companies/PLTR/estimate-revisions",
        frequency="quarterly", normalizedPeriod="Q3'26", order="asc"
    )

frame = revision_frame(payload, "Q3'26", "quarterly")
print(frame[["collectedDate", "revenueEstimate", "epsEstimate",
             "revenueChange", "epsChange"]].tail())
frame.to_csv("pltr-revisions-notebook.csv", index=False, na_rep="", mode="x")

revenueChange and epsChange subtract the previous collected value for that same target period. An EPS move from −0.10 to +0.05 is an absolute increase of 0.15 per share. A percentage change around zero or a negative base can be misleading, so this example does not calculate EPS percentage revisions.

Missing observations remain missing. The script does not forward-fill estimates, use the first non-null value as a hidden replacement baseline, or invent analyst publications between collection dates. If a prior value is missing, the adjacent change is blank.

05 · ANNUAL

Use a separate export for annual estimate revisions

Terminal · list annual periods
python estimate_revisions.py --ticker PLTR --frequency annual --list-periods
Terminal · export annual estimate revisions
python estimate_revisions.py --ticker PLTR --frequency annual --period "2027" --output-dir pltr-2027-estimates

Keep annual and quarterly estimates separate. Annual consensus is not constructed here by adding any four quarterly rows, and annual EPS is not combined with quarterly EPS. Select an annual period returned by discovery for your company.

To use another ticker, repeat discovery before selecting its period. Coverage and history length can differ. To refresh your export, run it again with a new output directory so your previous research snapshot remains intact.

06 · INTERPRET

What this estimate history can—and cannot—tell you

This workflow shows how stored consensus expectations evolved. It does not identify individual analysts, their publication times, dispersion or sample sizes. A collected observation is not a guaranteed point-in-time trading dataset.

Revenue uses the returned reporting currency; EPS is normalized per-share earnings. Do not automatically compare normalized EPS estimates with GAAP EPS from the latest earnings snapshot and label the difference an earnings surprise. First verify the accounting basis, target period and units.

If the reporting currency is absent, the CSV leaves it blank and the chart labels it as not returned. Resolve the units before combining the series with another monetary dataset.

07 · MICRON ANNUAL EXAMPLE

Add an annual earnings-revision check for Micron

Use this additional example to ask: have Micron’s revenue and EPS expectations for the same annual target moved up or down? Keep the Palantir exports above, and create a separate Micron research folder.

Terminal · discover Micron annual periods
python estimate_revisions.py --ticker MU --frequency annual --list-periods
Terminal · export Micron annual revisions
python estimate_revisions.py --ticker MU --frequency annual --period "2027" --output-dir mu-2027-estimates

Select 2027 from the returned annual labels for this example. The existing script produces the same revenue-and-EPS chart and CSV; the target stays fixed while collectedDate advances.

Python · compare Micron estimates over 60 days
import pandas as pd

frame = pd.read_csv("mu-2027-estimates/estimate-revisions.csv",
                    parse_dates=["collectedDate"])
frame = frame.sort_values("collectedDate")
# Compare the first and last collected snapshots in the latest 60-day window.
cutoff = frame["collectedDate"].max() - pd.Timedelta(days=60)
window = frame.loc[frame["collectedDate"] >= cutoff]
if len(window) < 2:
    raise ValueError("At least two collected snapshots are needed.")

first, last = window.iloc[0], window.iloc[-1]
comparison = pd.DataFrame({
    "firstEstimate": first[["revenueEstimate", "epsEstimate"]],
    "lastEstimate": last[["revenueEstimate", "epsEstimate"]],
})
comparison["absoluteRevision"] = (
    comparison["lastEstimate"] - comparison["firstEstimate"]
)
print("Target: MU annual 2027")
print("Collected:", first["collectedDate"].date(), "to",
      last["collectedDate"].date())
print(comparison)

The result shows the first estimate, last estimate and absolute revision for each measure, with the actual collection dates printed above them. This is a repeatable earnings-research check: run a fresh export into a new folder after the next update and compare the same annual target.

08 · TROUBLESHOOTING

Resolve missing history and request errors

No history for this period
Run --list-periods for the same ticker and frequency. Copy the exact label and keep quarterly labels inside double quotes in the terminal.
Unexpected duplicates
The script rejects duplicate collection dates for a single target period instead of arbitrarily selecting a value.
401, 403 or 429
Check key access and quota. Temporary GET failures are retried with backoff and Retry-After support. See API errors and limits.
Existing output directory
Use a new folder. An interrupted run can leave partial files for inspection; it will not overwrite them on the next run.

References: Estimate Revision Trends · pandas differences · Matplotlib subplots.