Build a custom OpenClaw skill that scans RSS feeds and web sources for breaking news, scores each headline for prediction market impact, and flags trading opportunities before the market adjusts. No API keys needed — just curl, jq, and python3.

Why Your Agent Needs a News Sentiment Scanner

Prediction markets are information markets. The edge goes to whoever processes new information fastest. A federal indictment drops, an injury report leaks, a central bank surprises — and the Polymarket contract that was trading at $0.65 should now be at $0.40. The window between news breaking and the market repricing is where autonomous agents earn their keep.

The problem: your agent doesn’t watch the news. It waits for you to tell it something happened. By the time you’ve read the headline, opened your terminal, and asked your agent to check the market, the price has already moved. Sharp bettors and market makers with automated pipelines captured the dislocation minutes ago.

This guide builds news-sentiment-scanner — a Layer 4 (Intelligence) skill that gives your agent a news feed. It scans public RSS sources, scores headlines for market relevance using keyword heuristics, and outputs a prioritized watchlist your agent can act on. Chain it with polymarket-monitor and ev-calculator and your agent goes from reactive to proactive.

What You’re Building

The news-sentiment-scanner skill teaches your OpenClaw agent five operations:

  1. Scan RSS feeds — Pull latest headlines from configurable news sources across sports, politics, economics, and crypto
  2. Score headlines — Rate each headline 0-100 for prediction market impact using keyword weights, recency, and source authority
  3. Search for related markets — Use web search to find Polymarket/Kalshi contracts related to a breaking story
  4. Generate a watchlist — Output a ranked list of news-market pairs sorted by urgency score
  5. Deep-dive a story — Fetch full article text and extract structured event data (who, what, when, market implications)

The skill uses curl, jq, and python3 — no external packages, no API keys, no paid subscriptions.

Prerequisites

  • OpenClaw installed and running — Any channel (WhatsApp, Telegram, Discord, WebChat)
  • curl, jq, and python3 — Pre-installed on macOS and most Linux distributions
  • Internet access — The skill fetches public RSS feeds and web pages

The Math Behind Sentiment Scoring

The scanner doesn’t use ML-based sentiment analysis — that would require external packages and GPU inference. Instead, it uses a deterministic keyword-weighted heuristic that runs in pure Python with no imports. The scoring formula:

score = (keyword_weight × source_multiplier) + recency_bonus

Keyword weights — Each headline is scanned for high-impact terms grouped by category:

CategoryKeywordsWeight
Legal/Politicalindicted, impeach, resign, sanction, subpoena, arrested25
Sports Injuryout, injury, ruled out, questionable, doubtful, suspended22
Economicrate cut, rate hike, default, recession, CPI, inflation20
Market Shockcrash, surge, upset, stunner, shocking, unprecedented18
Personnelfired, hired, traded, signed, retired, stepped down15
Routinescheduled, expected, confirmed, announced, reported5

Multiple keyword matches stack up to a cap of 50 from keywords alone.

Source multiplier — Not all sources are equal. Wire services break news first:

SourceMultiplier
AP News, Reuters1.5x
ESPN, BBC Sport1.3x
Bloomberg, WSJ1.4x
Polymarket Blog1.2x
Other1.0x

Recency bonus — Headlines less than 1 hour old get +20, less than 3 hours +10, less than 6 hours +5. Anything older gets no bonus.

A headline scoring 60+ is flagged as “actionable” — meaning your agent should check whether a related prediction market exists and whether the current price reflects the news.

The Complete SKILL.md

Create the skill directory:

mkdir -p ~/.openclaw/skills/news-sentiment-scanner

Create ~/.openclaw/skills/news-sentiment-scanner/SKILL.md with this content:

---
name: news-sentiment-scanner
description: "Scan news sources and RSS feeds for events that could move prediction market prices. Score headlines for market impact, flag urgent stories, and cross-reference with active markets. Use when asked about breaking news, market-moving events, or news sentiment."
metadata:
  openclaw:
    emoji: "📰"
    requires:
      bins: ["curl", "jq", "python3"]
---

# News Sentiment Scanner

Scan news and RSS feeds for market-moving events, score headline sentiment, and flag prediction market trading opportunities.

# When to Use

Use this skill when the user asks about:
- Breaking news that could affect prediction markets
- Scanning news for trading opportunities
- Sentiment analysis of current headlines
- Market-moving events in sports, politics, or economics
- News-driven trading signals
- Whether any recent news affects open positions

# RSS Feed Sources

Default feeds covering key prediction market verticals:

| Vertical | Feed URL |
|----------|----------|
| General Breaking | https://feeds.apnews.com/rss/apf-topnews |
| World News | https://feeds.reuters.com/reuters/topNews |
| US Politics | https://feeds.apnews.com/rss/apf-politics |
| Sports | https://www.espn.com/espn/rss/news |
| Economics | https://feeds.reuters.com/reuters/businessNews |
| Crypto | https://cointelegraph.com/rss |

The agent may add or substitute feeds based on context (e.g., if the user trades sports markets, prioritize ESPN).

# Operations

### 1. Scan RSS Feeds for Headlines

Fetch the latest headlines from all configured feeds:

```bash
for FEED_URL in \
  "https://feeds.apnews.com/rss/apf-topnews" \
  "https://feeds.reuters.com/reuters/topNews" \
  "https://feeds.apnews.com/rss/apf-politics" \
  "https://www.espn.com/espn/rss/news" \
  "https://feeds.reuters.com/reuters/businessNews" \
  "https://cointelegraph.com/rss"; do
  curl -s "$FEED_URL" | python3 -c "
import sys, xml.etree.ElementTree as ET
from datetime import datetime, timezone
try:
    tree = ET.parse(sys.stdin)
    root = tree.getroot()
    source = root.find('.//channel/title')
    src = source.text if source is not None else 'Unknown'
    for item in root.findall('.//item')[:10]:
        title = item.find('title')
        link = item.find('link')
        pub = item.find('pubDate')
        t = title.text if title is not None else ''
        l = link.text if link is not None else ''
        p = pub.text if pub is not None else ''
        print(f'{src}|{t}|{l}|{p}')
except: pass
"
done

2. Score Headlines for Market Impact

Take raw headlines (piped from operation 1 or pasted) and score them:

cat <<'HEADLINES' | python3 -c "
import sys, re
from datetime import datetime, timezone, timedelta

HIGH = {'indicted':25,'impeach':25,'resign':25,'sanction':25,'subpoena':25,'arrested':25,
        'out ':22,'injury':22,'ruled out':22,'questionable':22,'doubtful':22,'suspended':22,
        'rate cut':20,'rate hike':20,'default':20,'recession':20,'inflation':20,'cpi':20,
        'crash':18,'surge':18,'upset':18,'stunner':18,'shocking':18,'unprecedented':18,
        'fired':15,'hired':15,'traded':15,'signed':15,'retired':15,'stepped down':15}
LOW = {'scheduled':5,'expected':5,'confirmed':5,'announced':5,'reported':5}
SOURCES = {'AP News':1.5,'Reuters':1.5,'ESPN':1.3,'BBC':1.3,'Bloomberg':1.4,'WSJ':1.4,'Polymarket':1.2}

for line in sys.stdin:
    line = line.strip()
    if not line or '|' not in line: continue
    parts = line.split('|',3)
    if len(parts) < 3: continue
    src, title, url = parts[0], parts[1], parts[2]
    pub = parts[3] if len(parts) > 3 else ''

    kw_score = 0
    matched = []
    lower = title.lower()
    for kw, w in {**HIGH, **LOW}.items():
        if kw in lower:
            kw_score += w
            matched.append(kw)
    kw_score = min(kw_score, 50)

    src_mult = 1.0
    for s, m in SOURCES.items():
        if s.lower() in src.lower():
            src_mult = m
            break

    recency = 0  # default no bonus without parseable date

    score = min(int(kw_score * src_mult + recency), 100)
    flag = 'ACTION' if score >= 60 else 'WATCH' if score >= 30 else 'LOW'
    if score >= 30:
        print(f'[{flag}] {score} | {title} | {src} | {url}')
" <<'HEADLINES'
PASTE_HEADLINES_HERE
HEADLINES

Replace PASTE_HEADLINES_HERE with the output of operation 1. Or pipe directly:

## Pipe scan into scorer (combined one-liner)
(for FEED_URL in \
  "https://feeds.apnews.com/rss/apf-topnews" \
  "https://feeds.reuters.com/reuters/topNews" \
  "https://www.espn.com/espn/rss/news"; do
  curl -s "$FEED_URL" | python3 -c "
import sys, xml.etree.ElementTree as ET
try:
    tree = ET.parse(sys.stdin)
    root = tree.getroot()
    source = root.find('.//channel/title')
    src = source.text if source is not None else 'Unknown'
    for item in root.findall('.//item')[:8]:
        title = item.find('title')
        link = item.find('link')
        t = title.text if title is not None else ''
        l = link.text if link is not None else ''
        print(f'{src}|{t}|{l}|')
except: pass
"
done) | python3 -c "
import sys
HIGH = {'indicted':25,'impeach':25,'resign':25,'sanction':25,'arrested':25,
        'out ':22,'injury':22,'ruled out':22,'questionable':22,'suspended':22,
        'rate cut':20,'rate hike':20,'default':20,'recession':20,'inflation':20,
        'crash':18,'surge':18,'upset':18,'stunner':18,'shocking':18,
        'fired':15,'hired':15,'traded':15,'signed':15,'retired':15,'stepped down':15}
SOURCES = {'AP News':1.5,'Reuters':1.5,'ESPN':1.3,'BBC':1.3,'Bloomberg':1.4}
results = []
for line in sys.stdin:
    line = line.strip()
    if not line or '|' not in line: continue
    parts = line.split('|',3)
    if len(parts) < 3: continue
    src, title, url = parts[0], parts[1], parts[2]
    kw_score = 0
    lower = title.lower()
    for kw, w in HIGH.items():
        if kw in lower: kw_score += w
    kw_score = min(kw_score, 50)
    src_mult = 1.0
    for s, m in SOURCES.items():
        if s.lower() in src.lower(): src_mult = m; break
    score = min(int(kw_score * src_mult), 100)
    flag = 'ACTION' if score >= 60 else 'WATCH' if score >= 30 else 'LOW'
    if score >= 20:
        results.append((score, flag, title.strip(), src.strip(), url.strip()))
results.sort(key=lambda x: -x[0])
for s, f, t, src, u in results[:15]:
    print(f'[{f}] {s:3d} | {t} | {src}')
    if u: print(f'         {u}')
"

When a high-scoring headline is found, search for related prediction markets. Use OpenClaw’s built-in web search:

Search: "HEADLINE_KEYWORDS site:polymarket.com OR site:kalshi.com"

Or use curl to check Polymarket’s public API for matching markets:

curl -s "https://gamma-api.polymarket.com/markets?closed=false&limit=10&order=volume24hr&ascending=false&tag=CATEGORY" \

  | jq '[.[] | {question, outcomePrices, volume24hr: .volume24hr, endDate: .endDate}]'

Replace CATEGORY with the relevant tag: politics, sports, crypto, economics.

4. Generate Watchlist

Combine scored headlines with market matches into a structured watchlist. After running operations 1-3, format the output as:

NEWS-MARKET WATCHLIST — [timestamp]
==========================================

[ACTION] Score: 85
  Headline: "Senator X indicted on fraud charges"
  Source: AP News | 12 min ago
  Related Market: "Will Senator X resign by Q2 2026?" — Polymarket $0.35
  Signal: Market has NOT repriced. Potential +EV on YES.

[ACTION] Score: 72
  Headline: "Star player ruled out for playoffs"
  Source: ESPN | 28 min ago
  Related Market: NBA Championship futures
  Signal: Check team-specific futures for mispricing.

[WATCH] Score: 45
  Headline: "Fed officials signal rate pause"
  Source: Reuters | 2 hrs ago
  Related Market: "Fed rate cut by June?" — Kalshi $0.62
  Signal: Consistent with current pricing. Monitor for shift.

5. Deep-Dive a Story

For a specific headline, fetch the full article and extract structured data:

curl -s "ARTICLE_URL" | python3 -c "
import sys, re, html
text = sys.stdin.read()
## Strip HTML tags
clean = re.sub(r'<[^>]+>', ' ', text)
clean = html.unescape(clean)
## Extract first 2000 chars of article body
clean = re.sub(r'\s+', ' ', clean).strip()[:2000]
print(clean)
"

Then instruct the LLM to extract:

  • Who: Key entities (people, organizations, teams)
  • What: The core event
  • When: Timeline (already happened, expected, rumored)
  • Market Impact: Which prediction market categories are affected
  • Urgency: How quickly might markets reprice (minutes, hours, days)

Output Rules

  1. Always show the urgency score (0-100) and flag (ACTION/WATCH/LOW) for each headline
  2. ACTION items (60+) should include a related market search
  3. Sort output by score descending — most urgent first
  4. Include the source name and recency for every headline
  5. When a related market is found, show the current price and whether it appears to have already repriced
  6. Limit output to top 15 headlines unless the user asks for more
  7. Always include the scan timestamp so the user knows data freshness

Error Handling

  • If an RSS feed returns an error or times out, skip it and note which feeds were unreachable
  • If no headlines score above 30, report “No high-impact news detected” with the scan timestamp
  • If web search for related markets returns no results, note “No active market found for this event”
  • If python3 is unavailable, fall back to a simplified jq-only headline extractor (less accurate scoring)

## Test It

Restart OpenClaw (or wait for hot-reload if your version supports it), then try these prompts:

| Prompt                                                    | Expected Behavior                                                               |
| --------------------------------------------------------- | ------------------------------------------------------------------------------- |
| "Scan news for market-moving events"                      | Fetches RSS feeds, scores headlines, outputs ranked watchlist                   |
| "Any breaking news that affects prediction markets?"      | Same as above with emphasis on ACTION-level items                               |
| "Is there any sports news that could move betting lines?" | Scans ESPN feed, scores for injury/trade keywords, searches for related markets |
| "Deep dive on that indictment headline"                   | Fetches full article, extracts who/what/when/impact structure                   |
| "Set up a news watchlist for political markets"           | Configures scanner with politics-focused feeds, runs initial scan               |

Your agent reads the SKILL.md, selects the right feeds for the context, runs the curl + python3 pipeline, and formats a prioritized watchlist.

## How It Works Under the Hood

OpenClaw skills are not plugins that execute code directly. The SKILL.md is a set of instructions that the LLM (Claude, GPT, etc.) reads and follows at runtime.

When you ask "scan news for market movers," this is what happens:

User message → OpenClaw Gateway → LLM reads system prompt + active skills → LLM matches “news” + “market” to news-sentiment-scanner skill → LLM generates curl commands for configured RSS feeds → OpenClaw executes feed fetch via shell tool → XML parsed through python3, headlines extracted → Python scorer assigns urgency weights per headline → LLM searches for related prediction markets (web search or Polymarket API) → LLM combines scores + market data into watchlist format → Watchlist returned to user, sorted by urgency


The scoring heuristic is deterministic — same headline always gets the same base score. But the LLM adds contextual judgment when generating the watchlist: it knows that "Senator X indicted" matters more if there's an active resignation market than if there isn't. The SKILL.md provides the pipeline; the LLM provides the reasoning.

## Extending the Skill

### Add Cron-Based Monitoring

OpenClaw supports cron jobs. Set up a scanner that runs every 15 minutes and alerts you only when something actionable appears:

```json
{
  "cron": "*/15 * * * *",
  "prompt": "Run the news sentiment scanner. Only alert me on Telegram if any headline scores 60 or above AND has a matching prediction market."
}

This turns your agent into a 24/7 news desk that only pings you when there’s a trading opportunity — not every time a politician gives a speech.

Chain with Other Skills

The news-sentiment-scanner outputs structured watchlist data that downstream skills consume:

  • polymarket-monitor — When the scanner flags a political headline, polymarket-monitor checks if a related contract exists and pulls its current price and volume
  • kalshi-tracker — Same cross-reference for Kalshi event contracts, especially for economic and weather events
  • ev-calculator — Takes the scanner’s urgency signal plus current market price, estimates whether the news creates a +EV entry point
  • sharp-line-detector — Checks whether sportsbooks have already moved lines in response to the news (if they haven’t, the opportunity may still be live)
  • odds-scanner — For sports news (injuries, suspensions), pulls current odds to compare pre-news vs post-news pricing

The news scanner is the trigger layer — it detects the event. Everything downstream turns detection into a trade thesis.

Full Skill Series

This guide is part of the AgentBets OpenClaw Skills series. We’re building a complete library of betting-specific OpenClaw skills that map to the four layers of the Agent Betting Stack:

  • Layer 1 — Identity: Agent reputation tracking via Moltbook
  • Layer 2 — Wallet: Bankroll management, balance checking across platforms
  • Layer 3 — Trading: Odds scanning, Polymarket monitoring, Kalshi tracking, arbitrage detection
  • Layer 4 — Intelligence: EV calculation, Kelly sizing, CLV tracking, news sentiment (this guide)

Each skill is a standalone SKILL.md you can install independently or compose into a full autonomous betting pipeline.

What’s Next