HedgeFriend
← All posts
Research7 min readHedgeFriend

Wikipedia pageviews are a retail attention index

A free daily count of who is looking a company up. It forecasts volatility, not direction — and the baseline is the entire signal.

Every ticker has a Wikipedia article, and every day a certain number of people read it. That number is public, daily, free, and — unlike almost everything else labeled "sentiment" — it is a count of an actual human behavior rather than a model's opinion about some text. When someone hears a rumor, sees a headline, or gets a stock pitched to them at a party, a measurable fraction of them go look the company up.

The academic version of this idea is a decade old. Work by Moat, Preis and co-authors around 2013 showed that changes in Wikipedia article views for companies and financial topics carried information about subsequent market moves. The finding has held up better than most of that literature, largely because it is measuring something mechanical: attention precedes trading, because you have to notice a stock before you can buy it.

What follows is how to use the series without fooling yourself, because the naive version of this signal is wrong in three separate ways.

It is an attention signal, not a direction signal

This is the mistake that ruins most first attempts. A pageview spike tells you a lot of people suddenly care about a company. It tells you nothing at all about whether they like what they found. A fraud allegation and a blowout quarter produce the same shape.

So do not ask it to predict returns. Ask it to predict the things attention actually drives:

  • Realized volatility over the following days — the most robust of the three, and the one the original research leaned on.
  • Volume, and specifically the retail share of it.
  • The magnitude, not the sign, of the reaction to a scheduled event.
Attention is a variance forecast wearing a mean forecast's clothes. Used as the former it is genuinely useful; used as the latter it is a coin flip with extra steps.

The productive use is as a conditioner on a signal that does have a sign. An 8-K reporting an auditor change is a negative event whether or not anyone notices it; the same 8-K landing in the middle of an attention spike is a negative event that is going to get repriced quickly and violently. Attention tells you about the speed and size of the repricing, and lets the directional feed tell you about the direction.

Raw counts are meaningless; the baseline is the whole signal

Apple's article gets orders of magnitude more traffic on its quietest day than a mid-cap industrial gets during a scandal. Any cross-sectional comparison of raw views is a market-cap-and-brand-recognition ranking with a data feed attached.

What you want is each article compared against its own recent history. A few things make that less trivial than it sounds:

  1. 1.The distribution is fat-tailed and strictly positive. Work in logs, or your standard deviation will be dominated by the exact spikes you are trying to detect.
  2. 2.There is a strong weekday cycle. Traffic drops on weekends for essentially every company article, so a Saturday spike and a Tuesday spike of equal size are not equal events. De-seasonalize by day of week, or compare like days.
  3. 3.The baseline window has to exclude the event. A trailing window that includes the spike shrinks the very z-score you are computing. Use a lagged window — trailing 30 days ending several days before the day you are scoring.
  4. 4.Articles have slow secular drift as a company gets more or less famous. A rolling baseline handles this; a fixed one will slowly poison your thresholds.

The mapping is the hard part

Everything above assumes you know which article belongs to which ticker, and that assumption hides most of the real engineering. A few of the ways it goes wrong:

  • Company versus product. For some issuers the company article is a sleepy corporate stub while all the traffic sits on an article about a single product, a founder, or a controversy.
  • Conglomerates and holding companies, where the recognizable name and the listed entity are different articles.
  • Redirects and renames. Articles move. A mapping captured once and never revisited quietly decays into 404s and zero-view days that look like collapsing interest.
  • Ambiguity. A three-letter ticker is usually a disambiguation page for something else entirely.

We resolve an article title per symbol and store it, and the API returns that title alongside the counts precisely so you can audit it. If a series looks strange, check `page_title` first — the overwhelming majority of weird-looking attention data is a mapping problem rather than a market one.

One more honest caveat: the counts are all-agents, meaning they include automated traffic alongside human readers. Bots are a reasonably stable fraction over time, so they mostly inflate the level rather than manufacture spikes — but it is another reason to trust the deviation from baseline and distrust the absolute number.

Querying it

One request per ticker returns the daily series plus the article title being measured. The series runs to yesterday — the current day is always incomplete, so it is excluded rather than published as a partial count that would revise upward all afternoon.

curl
bash
curl -H "Authorization: Bearer $HEDGEFRIEND_KEY" \
  "https://api.hedgefriend.dev/v1/alt/wiki/NVDA?days=180"

And the scoring, with the lagged baseline and the day-of-week adjustment applied:

attention_z.py
python
import os, requests
import numpy as np
import pandas as pd

HEADERS = {"Authorization": f"Bearer {os.environ['HEDGEFRIEND_KEY']}"}

r = requests.get(
    "https://api.hedgefriend.dev/v1/alt/wiki/NVDA",
    params={"days": 365},
    headers=HEADERS,
    timeout=30,
)
r.raise_for_status()
payload = r.json()

df = pd.DataFrame(payload["points"])
df["date"] = pd.to_datetime(df["date"])
df = df.set_index("date").sort_index()

# Work in logs: the raw distribution is fat-tailed and strictly positive.
df["lv"] = np.log1p(df["views"])

# Strip the weekday cycle by demeaning within day-of-week.
df["lv"] -= df.groupby(df.index.dayofweek)["lv"].transform("mean")

# Baseline is lagged 5 days so the event cannot contaminate its own z-score.
base = df["lv"].shift(5).rolling(30)
df["z"] = (df["lv"] - base.mean()) / base.std()

print(payload["page_title"])
print(df.loc[df["z"] > 2, ["views", "z"]].tail(10))

A threshold around two standard deviations picks up roughly the events you would expect — earnings, litigation, index changes, the occasional viral product moment. Below that you are mostly reading noise; well above it you are usually reading a news cycle that the market has already had time to price.

How to test whether it works for you

We do not serve price data, so the join against returns is yours to make. That is not a limitation to work around so much as the right division of labor: you almost certainly already have a price source whose conventions your backtest agrees with, and reconciling two sources' idea of a split-adjusted close is a worse problem than fetching one series.

  1. 1.Compute the z-score above across a universe, not a single name. Attention signals look spectacular on the one ticker you picked because you remembered the spike.
  2. 2.Regress next-5-day realized volatility on the score. That is the relationship most likely to be there.
  3. 3.Then regress next-5-day return on the score, and expect roughly nothing. If you find a strong directional result, suspect your alignment before you celebrate — an off-by-one on the date index will happily manufacture one.
  4. 4.Check the decay. Most of the information is in the first day or two; a signal that only works with a same-day entry is a signal you cannot trade.

Done honestly, this is a modest, real, and unusually durable feature. It is not a strategy. It is a good regime flag and an excellent conditioner, it costs one request per ticker, and the underlying source is not going anywhere — which over a five-year horizon is worth more than most cleverer things.

Try it on your own data

The free tier covers 500 requests a day — enough to reproduce anything in this post.

Get a free key