Rotate to portrait

Vizual Stocks works best vertically on mobile.

VizualStocks API

PYTHON TUTORIAL · OWNERSHIP RESEARCH

Track institutional ownership changes with Python

Is institutional ownership rising or falling in the stocks you own? Build a Python watchlist with 30- and 90-day changes, insider ownership, bar charts and CSV exports.

01 · WATCHLIST

Is institutional ownership rising in your stocks?

A current ownership percentage tells you how much of a company institutions hold. A history helps you see whether that share is increasing or decreasing. Instead of checking each ticker manually, build one watchlist that compares them over the same lookback windows.

YOUR OWNERSHIP WATCHLISTSee what changed in your stocks

Institutional ownership · 90-day comparison

Latest percentage and changes in percentage points (pp)
TickerLatest %30d (pp)90d (pp)
PLTR64.75%-0.11+2.35
NVDA71.41%+0.09+0.53
TSLA43.67%-0.06-1.26
Sample run · September 19, 2026 cutoff. Latest observations: September 18 for PLTR/NVDA, September 19 for TSLA. Baselines: August 20 (30-day) and June 19 (90-day). Your report records the dates used for every stock.

This tutorial turns historical institutional and insider ownership data into a local HTML report, bar charts and two CSV files. Start with PLTR, NVDA and TSLA, then substitute the stocks you follow. The default run makes three read-only API requests before retries—one per ticker.

02 · SETUP

Set up your research workspace

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

Terminal · install dependencies
python -m pip install requests

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.

03 · RUN

Create an ownership report in one command

Terminal · build the watchlist
python ownership_watchlist.py --output-dir ownership-research

Open ownership-research/report.html in your browser. It ranks your stocks by the 90-day change in institutional ownership, shows both 30- and 90-day comparisons, and charts institutional and insider histories. It opens offline without an API key or a charting service.

The cutoff defaults to today in UTC. To use the date in the worked example:

Terminal · choose a fixed comparison date
python ownership_watchlist.py --tickers PLTR NVDA TSLA --as-of 2026-09-19 --output-dir ownership-september-19

Or use your own watchlist:

Terminal · choose your stocks
python ownership_watchlist.py --tickers MSFT NBIS GME --output-dir my-ownership-watchlist

Save each run to a new folder. A ticker without history or access stays in the report with a request note; it does not disappear from your watchlist.

04 · HISTORY

Get historical institutional ownership with Python

The historical ownership endpoint returns dated snapshots of the company’s ownership mix. It accepts inclusive from/to dates, order and an optional limit. The script requests ascending history through your cutoff without a limit, so older comparison baselines are available.

Python · inspect historical percentages
from datetime import datetime, timezone
from ownership_watchlist import (
    make_session, fetch_history, normalize_history,
)

as_of = datetime.now(timezone.utc).date()
with make_session() as session:
    payload = fetch_history(session, "PLTR", as_of)

rows = normalize_history(payload)
for row in rows[-5:]:
    print(row["observedDate"], row["institutionsPercent"],
          row["insidersPercent"])
print("Observations:", len(rows))

Keep the downloaded file next to your notebook to import these functions. The important fields are:

observedDate
The saved snapshot date. Consecutive snapshots can contain the same reading.
institutionsPercent · insidersPercent
Observed percentages of shares held by institutions and insiders. A value of 64.75 means 64.75%, not 6,475%.
undisclosedPercent · interpretationFlags
The calculated remainder and flags for unusual readings. Both remain in the history export.

05 · COMPARE

Which stocks have increasing institutional ownership?

Subtract each stock’s baseline percentage from its latest percentage. Sort those changes to find the largest increases and decreases within your watchlist.

CHANGE IN PERCENTAGE POINTS64.75% − 62.40% = +2.35 ppPLTR · June 19 to September 18, 2026
Python · rank the watchlist
from ownership_watchlist import summarize, rank_watchlist

# Continue with the imports and as_of date above.
watchlist = []
with make_session() as session:
    for ticker in ["PLTR", "NVDA", "TSLA"]:
        payload = fetch_history(session, ticker, as_of)
        history = normalize_history(payload)
        watchlist.append(summarize(ticker, history, as_of))

for row in rank_watchlist(watchlist):
    print(row["ticker"], row["institutionsPercent"],
          row["institutionsChangePp30d"],
          row["institutionsChangePp90d"])

For a September 19 cutoff, the 90-day target is June 21. If there is no observation on that date, the script uses the last reading on or before it—June 19 in this example. It does the same for the latest reading and the 30-day boundary.

The report shows actual dates under Comparison dates. If a boundary has no earlier observation, or that observation is more than 14 days old, the affected change stays blank. Change that tolerance with --max-age-days. Missing history is never treated as zero, and the script never substitutes a reading after the target date.

This is a ranking of observed ownership-percentage changes, not a count of institutional purchases. The 14-day check measures gaps between saved snapshots; it does not certify the underlying source’s freshness.

06 · INSIDERS

Compare the ownership trends over time

The report gives each company separate bar charts for institutional and insider ownership. It uses the last actual snapshot in each month, displays up to 18 observed months, and retains every returned observation in ownership-history.csv.

Each chart shows its own percentage scale. Missing months remain gaps, not invented observations, and hovering a bar reveals the exact snapshot date and percentage. The monthly bars are selected readings—not monthly averages.

Use insidersChangePp30d and insidersChangePp90d in watchlist.csv to compare insider ownership alongside institutions. A change in insider ownership percentage is not the same dataset as individual insider buys and sells.

07 · REFRESH

Refresh the stocks you follow

Pick a threshold to focus your review. This example selects increases or decreases of at least half a percentage point over the 90-day window:

Python · flag watchlist changes
# Flag watchlist changes of at least 0.5 percentage points.
# Use the watchlist created in the previous example.
threshold_pp = 0.5
for row in rank_watchlist(watchlist):
    change = row["institutionsChangePp90d"]
    if change is not None and abs(change) >= threshold_pp:
        direction = "increased" if change > 0 else "decreased"
        print(row["ticker"], direction, f"{abs(change):.2f} pp",
              row["baselineDate90d"], "to", row["latestObservedDate"])

This is a research filter you choose, not a recommended trading threshold. It checks the lookback change, not a new event since your last run.

Terminal · save a fresh report
python ownership_watchlist.py --tickers PLTR NVDA TSLA --output-dir ownership-next-run

The new folder preserves your earlier results. To inspect adjacent snapshots instead, use institutionsChangePp and insidersChangePp in the full-history CSV. An unchanged saved reading produces zero; the first observation has no prior change.

08 · INTERPRET

Is increasing institutional ownership bullish?

Investors often watch rising institutional ownership as a sign of stronger institutional participation. This workflow lets you measure that trend rather than rely on isolated screenshots. It does not, by itself, show fresh fund purchases or predict a stock’s next move: the percentage can also change when the share count or the source’s reported holdings change.

Can I see which funds are buying?

This endpoint provides aggregate ownership percentages, not named fund holdings or transaction records. Use it to identify changes worth investigating. For filing-based research, remember that reporting periods and publication dates differ; the SEC’s Form 13F reference explains the reporting timetable.

Is the remaining percentage retail ownership?

No. undisclosedPercent is calculated as 100 − institutionsPercent − insidersPercent. It can be negative when the reported components exceed 100%. The script preserves that value and the API’s interpretation flags instead of relabeling it “retail” or forcing the mix into a pie chart.

What else can I compare it with?

Pair the results with historical short interest or the company’s operating KPIs in a Python and Excel research workbook. Keep the dates and definitions beside each series: short interest as a percentage of float and institutional ownership as a percentage of shares have different denominators.

09 · EXPORTS

Take the ownership data into your workflow

report.html
Your ranked watchlist, bar charts, comparison dates and any unavailable-ticker notes. Opens locally without external assets.
watchlist.csv
One row per requested ticker: latest percentages, 30-/90-day changes, baseline dates, snapshot gaps and comparison statuses. Open it directly in Excel.
ownership-history.csv
All returned observations through your cutoff, with adjacent-observation changes, the signed remainder and interpretation flags. Numeric values stay numeric; missing values stay blank.
metadata.json
Retrieval time, cutoff, ticker list, comparison settings, API methodology and request errors. No API key is saved.

Why is a comparison blank?

Check comparisonStatus30d or comparisonStatus90d. The baseline may predate available history, sit too far before the target, or contain a missing value. The report keeps the latest available percentage visible even when it cannot calculate a usable change.

What if the request fails?

A 401 stops the script so you can check your key. A 403 or 404 is recorded for that ticker while other stocks continue. The company directory identifies sandbox-eligible companies; the API error reference explains access and rate limits. Temporary failures get bounded retries. An existing output folder is never overwritten.

Reference: Historical ownership endpoint, parameters and response fields.