Reddit finance communities like r/wallstreetbets, r/stocks, and r/investing surface retail sentiment hours before it shows up in price action. This scanner uses the Scavio Reddit search endpoint to pull recent discussions mentioning stock tickers, scores them by sentiment and engagement, and outputs a ranked watchlist. Each subreddit scan costs $0.005.
Prerequisites
- Python 3.8+
- requests library
- A Scavio API key from scavio.dev
- Target tickers or stock-related keywords
Walkthrough
Step 1: Set up the Reddit stock scanner
Configure the scanner with target subreddits and ticker extraction.
import os, requests, re
from collections import defaultdict
API_KEY = os.environ['SCAVIO_API_KEY']
SH = {'x-api-key': API_KEY, 'Content-Type': 'application/json'}
SUBREDDITS_QUERIES = ['wallstreetbets stock', 'stocks investing', 'investing portfolio']
TICKER_PATTERN = re.compile(r'\b[A-Z]{2,5}\b')
COMMON_WORDS = {'THE', 'AND', 'FOR', 'ARE', 'BUT', 'NOT', 'YOU', 'ALL', 'CAN', 'HER',
'WAS', 'ONE', 'OUR', 'OUT', 'HAS', 'ITS', 'HIS', 'HOW', 'MAY', 'NEW'}
def extract_tickers(text):
found = TICKER_PATTERN.findall(text)
return [t for t in found if t not in COMMON_WORDS and len(t) >= 2]
print('Reddit stock scanner configured.')Step 2: Scan Reddit for stock discussions
Search Reddit finance communities and extract ticker mentions with context.
def scan_reddit(query):
data = requests.post('https://api.scavio.dev/api/v1/search',
headers=SH, json={'query': query, 'platform': 'reddit', 'country_code': 'us'}).json()
results = data.get('organic_results', [])[:15]
mentions = defaultdict(list)
for r in results:
text = f"{r.get('title', '')} {r.get('snippet', '')}"
tickers = extract_tickers(text)
for t in tickers:
mentions[t].append({'title': r.get('title', '')[:80],
'snippet': r.get('snippet', '')[:120], 'link': r.get('link', '')})
return mentions
all_mentions = defaultdict(list)
for q in SUBREDDITS_QUERIES:
mentions = scan_reddit(q)
for ticker, posts in mentions.items():
all_mentions[ticker].extend(posts)
print(f' {q}: {len(mentions)} tickers found')
print(f'Total unique tickers: {len(all_mentions)}')Step 3: Score tickers by sentiment and volume
Assign sentiment scores based on context keywords and rank by mention volume.
BULLISH = ['buy', 'moon', 'calls', 'bullish', 'undervalued', 'squeeze', 'breakout', 'long']
BEARISH = ['sell', 'puts', 'bearish', 'overvalued', 'crash', 'short', 'dump', 'avoid']
def score_ticker(ticker, posts):
bull = bear = 0
for p in posts:
text = f"{p['title']} {p['snippet']}".lower()
bull += sum(1 for w in BULLISH if w in text)
bear += sum(1 for w in BEARISH if w in text)
total = bull + bear or 1
sentiment = (bull - bear) / total
return {'ticker': ticker, 'mentions': len(posts), 'bullish': bull,
'bearish': bear, 'sentiment': round(sentiment, 2)}
scored = [score_ticker(t, p) for t, p in all_mentions.items()]
scored.sort(key=lambda x: x['mentions'], reverse=True)
print(f'\nTop tickers by mention volume:')
for s in scored[:10]:
signal = 'BULL' if s['sentiment'] > 0.3 else 'BEAR' if s['sentiment'] < -0.3 else 'NEUTRAL'
print(f' ${s["ticker"]:5} | {s["mentions"]:3} mentions | sentiment: {s["sentiment"]:+.2f} | {signal}')Step 4: Generate a daily watchlist
Filter high-signal tickers and output a ranked watchlist.
def generate_watchlist(scored, min_mentions=2):
watchlist = [s for s in scored if s['mentions'] >= min_mentions]
watchlist.sort(key=lambda x: abs(x['sentiment']) * x['mentions'], reverse=True)
cost = len(SUBREDDITS_QUERIES) * 0.005
print(f'\n=== Reddit Stock Watchlist ({len(watchlist)} tickers) ===')
print(f'Cost: ${cost:.3f} ({len(SUBREDDITS_QUERIES)} queries)')
for i, s in enumerate(watchlist[:15], 1):
signal = 'BULL' if s['sentiment'] > 0.3 else 'BEAR' if s['sentiment'] < -0.3 else 'MIXED'
print(f' {i:2}. ${s["ticker"]:5} | {s["mentions"]:3}x | {signal:7} | score: {s["sentiment"]:+.2f}')
return watchlist
watchlist = generate_watchlist(scored)Python Example
import os, requests, re
from collections import defaultdict
SH = {'x-api-key': os.environ['SCAVIO_API_KEY'], 'Content-Type': 'application/json'}
TICKER_RE = re.compile(r'\b[A-Z]{2,5}\b')
SKIP = {'THE','AND','FOR','ARE','NOT','YOU','ALL','CAN','HAS','NEW'}
def scan(query):
data = requests.post('https://api.scavio.dev/api/v1/search',
headers=SH, json={'query': query, 'platform': 'reddit', 'country_code': 'us'}).json()
tickers = defaultdict(int)
for r in data.get('organic_results', [])[:10]:
for t in TICKER_RE.findall(f"{r.get('title','')} {r.get('snippet','')}"):
if t not in SKIP: tickers[t] += 1
for t, c in sorted(tickers.items(), key=lambda x: -x[1])[:5]:
print(f' ${t}: {c} mentions')
scan('wallstreetbets stock picks')JavaScript Example
const SH = { 'x-api-key': process.env.SCAVIO_API_KEY, 'Content-Type': 'application/json' };
async function scan(query) {
const data = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST', headers: SH,
body: JSON.stringify({ query, platform: 'reddit', country_code: 'us' })
}).then(r => r.json());
const tickers = {};
const skip = new Set(['THE','AND','FOR','ARE','NOT','YOU','ALL','CAN','HAS','NEW']);
for (const r of (data.organic_results || []).slice(0, 10)) {
const text = `${r.title || ''} ${r.snippet || ''}`;
for (const m of text.matchAll(/\b[A-Z]{2,5}\b/g)) {
if (!skip.has(m[0])) tickers[m[0]] = (tickers[m[0]] || 0) + 1;
}
}
Object.entries(tickers).sort((a,b) => b[1]-a[1]).slice(0,5)
.forEach(([t,c]) => console.log(` $${t}: ${c} mentions`));
}
scan('wallstreetbets stock picks').catch(console.error);Expected Output
wallstreetbets stock: 8 tickers found
stocks investing: 6 tickers found
investing portfolio: 5 tickers found
Total unique tickers: 14
Top tickers by mention volume:
$NVDA | 7 mentions | sentiment: +0.65 | BULL
$TSLA | 5 mentions | sentiment: -0.40 | BEAR
$AAPL | 4 mentions | sentiment: +0.33 | BULL
$AMD | 3 mentions | sentiment: +0.50 | BULL
$SPY | 3 mentions | sentiment: +0.20 | NEUTRAL
=== Reddit Stock Watchlist (8 tickers) ===
Cost: $0.015 (3 queries)