Python Stock Sentiment Examples: Five Scripts for Bullish and Bearish Reads
Five working Python examples for stock sentiment data: one stock today and over 30 days, whether a mention spike is good or bad news, the most bullish names in a watchlist, market-wide breadth, and sentiment lined up against price. One pip install, one free key, each script runs as written.
Stock sentiment in Python is pip install sentisense, one free API key, and the five scripts below. Each one runs as written. Together they answer the questions developers put to sentiment data: what the read on one stock is today and over the last month, whether a burst of mentions is good or bad news, which names in a watchlist draw the most bullish coverage, how the whole market leans, and how sentiment lines up with price.
On this page an analysis is one news article or social post our models read as bullish or bearish for a stock. Counts of analyses come from news, Reddit, X, YouTube and other sources together. The stock sentiment API page covers methodology and coverage; this page is code.
Setup
pip install sentisense
export SENTISENSE_API_KEY=ss_live_YOUR_KEY
The scripts need Python 3.10 or later. Every script starts the same way:
import os
from sentisense import SentiSenseClient
client = SentiSenseClient(api_key=os.environ["SENTISENSE_API_KEY"])
1. What is the sentiment on one stock, today and over 30 days?
get_stock_sentiment returns the whole picture in one call: today's read and SentiSense Score, the 30-day average and its change, a trend, mention volume, and the tone of each source. This script prints the direction, the volume and the source split.
s = client.get_stock_sentiment("NVDA").data
print(f"{s['ticker']} as of {s['asOf']}")
print(f"today: read={s['latestDirection']} mentions={s['mentions']}")
print(f"30 days: {s['direction']} ({s['scoreLabel']}), trend {s['trend']}")
print(f"mentions/day, 30-day avg: {s['mentionsAvg30d']}")
for src in s["bySource"][:4]:
print(f" {src['source']:12} {src['mentionShare']:>4.0f}% of mentions {src['direction']:8} {src['value']:+.2f}")
Output on 2026-09-24:
NVDA as of 2026-09-24
today: read=Bullish mentions=249
30 days: Bullish (Strong Bullish), trend DOWN
mentions/day, 30-day avg: 353
News 69% of mentions Bullish +0.39
Reddit 13% of mentions Bullish +0.10
X 10% of mentions Bullish +0.33
YouTube 6% of mentions Bullish +0.21
The same payload carries sentisenseScore, sentisenseScoreAvg30d and sentisenseScoreDelta30d when you want the numbers. sentisenseScore and latestDirection are None until the day's first analytics run lands, mid-morning Eastern; scoreLabel, direction and the 30-day fields are present at any hour. mentionShare is a whole-number percent per source, rounded independently, so the shares can sum to 99 or 101.
2. Is a mention spike good news or bad news?
A mention count says how loud the conversation is, not which way it leans. Each daily point of the sentisense metric carries bull, bear and directional counts under metricValue["properties"]. This script finds each stock's loudest day of the last 30 and reads the split for that day.
import time, statistics
from datetime import datetime
from zoneinfo import ZoneInfo
NY = ZoneInfo("America/New_York")
start = int(time.time() * 1000) - 30 * 86_400_000
for ticker in ["CRM", "UNH"]:
mentions = client.get_metrics(ticker, metric_type="mentions", start_time=start)
score = client.get_metrics(ticker, metric_type="sentisense", start_time=start)
counts = {p["timestamp"]: p["metricValue"].get("properties", {}) for p in score}
median = statistics.median(p.get("value", 0) for p in mentions)
peak = max(mentions, key=lambda p: p.get("value", 0))
day = datetime.fromtimestamp(peak["timestamp"] / 1000, NY).date()
c = counts.get(peak["timestamp"], {})
print(f"{ticker}: peak {day} mentions={peak['value']:.0f} ({peak['value'] / median:.1f}x the 30-day median) "
f"bullish={c.get('bull', 0):.0f} bearish={c.get('bear', 0):.0f}")
Output on 2026-09-24:
CRM: peak 2026-08-27 mentions=324 (3.9x the 30-day median) bullish=197 bearish=10
UNH: peak 2026-09-09 mentions=74 (3.4x the 30-day median) bullish=22 bearish=32
Two spikes of similar size, opposite splits: bullish analyses dominated one, and bearish analyses outnumbered bullish on the other. Points are daily, one per New York calendar day, stamped at midnight Eastern, so the two series join on timestamp. The last point is the current day so far.
3. Which stocks in my watchlist have the most bullish analyses this week?
Sum bull and bear over seven days for each ticker and rank by bullish share.
import time
watchlist = ["AAPL", "MSFT", "NVDA", "AMZN", "META", "GOOGL", "TSLA", "AMD"]
start = int(time.time() * 1000) - 7 * 86_400_000
rows = []
for ticker in watchlist:
points = client.get_metrics(ticker, metric_type="sentisense", start_time=start)
bull = sum(p["metricValue"].get("properties", {}).get("bull", 0) for p in points)
bear = sum(p["metricValue"].get("properties", {}).get("bear", 0) for p in points)
rows.append((ticker, bull, bear, bull / (bull + bear) if bull + bear else 0.0))
for ticker, bull, bear, share in sorted(rows, key=lambda r: r[3], reverse=True):
print(f"{ticker:6} bullish={bull:5.0f} bearish={bear:5.0f} bullish share={share:.0%}")
Output on 2026-09-24:
AMD bullish= 613 bearish= 97 bullish share=86%
AMZN bullish= 1135 bearish= 333 bullish share=77%
AAPL bullish= 174 bearish= 55 bullish share=76%
NVDA bullish= 1009 bearish= 341 bullish share=75%
META bullish= 1186 bearish= 441 bullish share=73%
TSLA bullish= 543 bearish= 367 bullish share=60%
MSFT bullish= 467 bearish= 324 bullish share=59%
GOOGL bullish= 756 bearish= 528 bullish share=59%
A share is only as good as its sample. Print bull + bear beside it, as here, or set a floor before ranking, so a name with a handful of analyses cannot top the list.
4. How many stocks are bullish versus bearish today?
Sentiment breadth is the tone version of an advance/decline line: each covered stock casts one vote by its mean sentiment. It is a plain REST call with the same key.
import requests
resp = requests.get(
"https://app.sentisense.ai/api/v1/sentiment/breadth",
headers={"X-SentiSense-API-Key": os.environ["SENTISENSE_API_KEY"]},
timeout=30,
)
resp.raise_for_status()
breadth = resp.json()
print(f"as of {breadth['asOf']}, stocks with at least {breadth['minMentions']} mentions count")
for day in breadth["series"][-5:]:
print(f"{day['date']} covered={day['coveredStocks']:4} bullish={day['bullish']:4} "
f"neutral={day['neutral']:4} bearish={day['bearish']:4} net={day['netBreadth']:+6.1f} pts "
f"bullish by mentions={day['bullishMentionPct']:.0f}%")
Output on 2026-09-24:
as of 2026-09-24, stocks with at least 5 mentions count
2026-09-20 covered= 186 bullish= 121 neutral= 33 bearish= 32 net= +47.9 pts bullish by mentions=63%
2026-09-21 covered= 427 bullish= 306 neutral= 54 bearish= 67 net= +56.0 pts bullish by mentions=77%
2026-09-22 covered= 486 bullish= 354 neutral= 57 bearish= 75 net= +57.4 pts bullish by mentions=76%
2026-09-23 covered= 547 bullish= 381 neutral= 75 bearish= 91 net= +53.0 pts bullish by mentions=76%
2026-09-24 covered= 541 bullish= 344 neutral= 82 bearish= 115 net= +42.3 pts bullish by mentions=68%
coveredStocks is the day's denominator, and it is lower on a quiet day such as a Sunday. When the stock-weighted and mention-weighted shares disagree, a few heavily discussed names are carrying the tone. series holds the daily history back to July 2026 for charting.
5. How does sentiment line up with price?
Pull daily bars and the daily Score for one ticker, join them on the New York date, and compare the two series.
# uses time, statistics, datetime and NY from script 2
ticker = "TSLA"
day = lambda ts: datetime.fromtimestamp(ts / 1000, NY).date()
bars = client.get_stock_chart(ticker, timeframe="3M") # daily bars, oldest first
start = int(time.time() * 1000) - 90 * 86_400_000
score = {day(p["timestamp"]): p for p in
client.get_metrics(ticker, metric_type="sentisense", start_time=start) if "value" in p}
rows, prev = [], None
for b in bars:
d = day(b["timestamp"])
if prev and d in score:
ret = (b["close"] / prev - 1) * 100
props = score[d]["metricValue"].get("properties", {})
rows.append((d, b["close"], ret, score[d]["value"], props.get("bull", 0), props.get("bear", 0)))
prev = b["close"]
for d, close, ret, s, bull, bear in rows[-5:]:
print(f"{d} close={close:8.2f} change={ret:+5.1f}% bullish={bull:4.0f} bearish={bear:4.0f}")
scores, rets = [r[3] for r in rows], [r[2] for r in rows]
print(f"\n{len(rows)} trading days lined up")
print(f"score vs same-day change: r = {statistics.correlation(scores, rets):+.2f}")
print(f"score vs next-day change: r = {statistics.correlation(scores[:-1], rets[1:]):+.2f}")
Output on 2026-09-24:
2026-09-18 close= 364.27 change= -0.5% bullish= 70 bearish= 66
2026-09-21 close= 375.30 change= +3.0% bullish= 133 bearish= 90
2026-09-22 close= 378.90 change= +1.0% bullish= 111 bearish= 68
2026-09-23 close= 380.12 change= +0.3% bullish= 98 bearish= 41
2026-09-24 close= 377.94 change= -0.6% bullish= 50 bearish= 44
61 trading days lined up
score vs same-day change: r = +0.53
score vs next-day change: r = +0.06
On this run the Score tracked the same day's price change far more closely than the next day's. That is one ticker over one window; rerun it on your own names and dates before drawing anything from it. The 3M timeframe returns daily bars; 1M and shorter return intraday bars, which do not join one-to-one with the daily Score.
What the free key returns
All five scripts run on a free API key. get_stock_sentiment, every get_metrics series used here, sentiment breadth and daily chart bars are served in full on every tier, with no preview trimming. The free key limits volume: 1,000 requests a month and 30 a minute. Script 1 is one request, script 2 is four, script 3 is one per watchlist ticker, script 4 is one and script 5 is two. PRO removes the monthly cap and raises the rate limit to 300 a minute, which matters once script 3 runs over a few hundred tickers on a schedule.
An AI agent gets the same answers without the script: npx -y sentisense sentiment TSLA in the sentisense CLI, a tool on the MCP connector, or the stock-sentiment skill for Claude Code, Codex and OpenClaw. Field-by-field reference: the Metrics API, the Stocks API and the Market Mood API. Same shape, other verticals: Python political trading examples and Python earnings examples.
Ready to run script one? Get a free API key → and paste it into the export line above.