Tutorial

How to Build a Prediction Market Data Agent

Build an agent that combines live news search with prediction market data. Cross-reference market odds against current events for informed analysis.

Prediction markets like Polymarket and Kalshi price event probabilities based on trader sentiment, but traders often react slowly to breaking news. An agent that combines real-time news search with prediction market data can identify discrepancies: a market prices an event at 30% but recent news strongly suggests it will happen. This tutorial builds a Python agent that fetches prediction market positions via their public APIs, searches for the latest news on each market question via Scavio, and produces a briefing that highlights markets where news sentiment diverges from current odds. The search cost is $0.005 per market question checked.

Prerequisites

  • Python 3.10+ installed
  • requests library installed
  • A Scavio API key from scavio.dev
  • Familiarity with REST APIs and JSON

Walkthrough

Step 1: Fetch active prediction markets

Pull active markets from Polymarket's public API. Each market has a question, current probability, and metadata. Filter to markets with enough volume to be meaningful.

Python
import os, requests, json
from datetime import datetime

SCAVIO_KEY = os.environ['SCAVIO_API_KEY']
SEARCH_HEADERS = {'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json'}

def get_active_markets(min_volume=50000, limit=20):
    resp = requests.get('https://gamma-api.polymarket.com/markets',
        params={'limit': limit, 'active': True, 'ascending': False,
                'order': 'volume'})
    markets = resp.json()
    return [m for m in markets
        if float(m.get('volume', 0)) >= min_volume
        and m.get('question')]

Step 2: Search for recent news on each market question

For each market, search Google News via the Scavio API with the market question as the query. Collect the top 5 headlines and snippets as the news context.

Python
def search_news(question):
    resp = requests.post('https://api.scavio.dev/api/v1/search',
        headers=SEARCH_HEADERS,
        json={'query': question, 'country_code': 'us'})
    data = resp.json()
    results = data.get('organic_results', [])[:5]
    news_items = []
    for r in results:
        news_items.append({
            'title': r.get('title', ''),
            'snippet': r.get('snippet', ''),
            'url': r.get('link', ''),
            'date': r.get('date', ''),
        })
    return news_items

Step 3: Analyze sentiment and produce a briefing

For each market, compare the news headlines against the market probability. Flag markets where news strongly suggests a different outcome than the market price implies.

Python
def analyze_market(market, news):
    question = market['question']
    probability = float(market.get('outcomePrices', '[0.5]').strip('[]').split(',')[0])
    positive_words = ['will', 'confirmed', 'expected', 'likely', 'approved', 'passed', 'wins']
    negative_words = ['unlikely', 'rejected', 'denied', 'fails', 'canceled', 'delayed']
    headline_text = ' '.join(n['title'].lower() + ' ' + n['snippet'].lower() for n in news)
    pos_count = sum(1 for w in positive_words if w in headline_text)
    neg_count = sum(1 for w in negative_words if w in headline_text)
    news_sentiment = 'POSITIVE' if pos_count > neg_count else 'NEGATIVE' if neg_count > pos_count else 'NEUTRAL'
    divergence = False
    if news_sentiment == 'POSITIVE' and probability < 0.4:
        divergence = True
    elif news_sentiment == 'NEGATIVE' and probability > 0.6:
        divergence = True
    return {
        'question': question,
        'market_probability': f"{probability:.0%}",
        'news_sentiment': news_sentiment,
        'divergence': divergence,
        'top_headline': news[0]['title'] if news else '',
        'source': news[0]['url'] if news else '',
    }

Step 4: Run the full agent and output the briefing

Combine all steps: fetch markets, search news for each, analyze, and print a briefing sorted by divergence signals.

Python
def run_agent():
    markets = get_active_markets(limit=15)
    print(f'Analyzing {len(markets)} active markets...\n')
    briefing = []
    for m in markets:
        news = search_news(m['question'])
        analysis = analyze_market(m, news)
        briefing.append(analysis)
    divergent = [b for b in briefing if b['divergence']]
    aligned = [b for b in briefing if not b['divergence']]
    if divergent:
        print('--- DIVERGENCE SIGNALS ---')
        for b in divergent:
            print(f"  {b['question'][:70]}")
            print(f"  Market: {b['market_probability']} | News: {b['news_sentiment']}")
            print(f"  Headline: {b['top_headline'][:80]}")
            print()
    print(f'--- SUMMARY ---')
    print(f'{len(divergent)} divergence signals, {len(aligned)} aligned')
    print(f'Cost: ${len(markets) * 0.005:.3f}')
    return briefing

run_agent()

Python Example

Python
import os, requests

SCAVIO_KEY = os.environ['SCAVIO_API_KEY']
SH = {'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json'}

def get_markets(limit=10):
    return requests.get('https://gamma-api.polymarket.com/markets',
        params={'limit': limit, 'active': True, 'order': 'volume',
                'ascending': False}).json()

def search_news(question):
    data = requests.post('https://api.scavio.dev/api/v1/search',
        headers=SH, json={'query': question, 'country_code': 'us'}).json()
    return data.get('organic_results', [])[:5]

def run():
    markets = get_markets()
    for m in markets:
        if not m.get('question'): continue
        news = search_news(m['question'])
        prob = float(m.get('outcomePrices', '[0.5]').strip('[]').split(',')[0])
        headlines = ' '.join(n.get('title', '').lower() for n in news)
        pos = sum(1 for w in ['confirmed', 'approved', 'wins', 'likely'] if w in headlines)
        neg = sum(1 for w in ['rejected', 'unlikely', 'fails', 'denied'] if w in headlines)
        sentiment = 'POS' if pos > neg else 'NEG' if neg > pos else 'NEUTRAL'
        flag = '*' if (sentiment == 'POS' and prob < 0.4) or (sentiment == 'NEG' and prob > 0.6) else ' '
        print(f'{flag} [{prob:.0%}] {m["question"][:60]} | News: {sentiment}')
    print(f'Cost: ${len(markets) * 0.005:.3f}')

run()

JavaScript Example

JavaScript
const SCAVIO_KEY = process.env.SCAVIO_API_KEY;
const SH = { 'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json' };

async function getMarkets(limit = 10) {
  return fetch(`https://gamma-api.polymarket.com/markets?limit=${limit}&active=true&order=volume&ascending=false`)
    .then(r => r.json());
}

async function searchNews(question) {
  const data = await fetch('https://api.scavio.dev/api/v1/search', {
    method: 'POST', headers: SH, body: JSON.stringify({ query: question, country_code: 'us' })
  }).then(r => r.json());
  return (data.organic_results || []).slice(0, 5);
}

async function run() {
  const markets = await getMarkets();
  for (const m of markets) {
    if (!m.question) continue;
    const news = await searchNews(m.question);
    const prob = parseFloat((m.outcomePrices || '[0.5]').replace(/[\[\]]/g, '').split(',')[0]);
    const headlines = news.map(n => (n.title || '').toLowerCase()).join(' ');
    const pos = ['confirmed', 'approved', 'wins'].filter(w => headlines.includes(w)).length;
    const neg = ['rejected', 'unlikely', 'fails'].filter(w => headlines.includes(w)).length;
    const sentiment = pos > neg ? 'POS' : neg > pos ? 'NEG' : 'NEUTRAL';
    const flag = (sentiment === 'POS' && prob < 0.4) || (sentiment === 'NEG' && prob > 0.6) ? '*' : ' ';
    console.log(`${flag} [${(prob * 100).toFixed(0)}%] ${m.question.slice(0, 60)} | News: ${sentiment}`);
  }
  console.log(`Cost: $${(markets.length * 0.005).toFixed(3)}`);
}

run().catch(console.error);

Expected Output

JSON
Analyzing 15 active markets...

--- DIVERGENCE SIGNALS ---
  Will the Fed cut interest rates in June 2026?
  Market: 28% | News: POSITIVE
  Headline: Fed officials signal June rate cut is likely amid cooling inflation

  Will SpaceX complete Starship orbital flight by July 2026?
  Market: 65% | News: NEGATIVE
  Headline: SpaceX delays Starship test flight after engine review

--- SUMMARY ---
2 divergence signals, 13 aligned
Cost: $0.075

Related Tutorials

Frequently Asked Questions

Most developers complete this tutorial in 15 to 30 minutes. You will need a Scavio API key (free tier works) and a working Python or JavaScript environment.

Python 3.10+ installed. requests library installed. A Scavio API key from scavio.dev. Familiarity with REST APIs and JSON. A Scavio API key gives you 250 free credits per month.

Yes. The free tier includes 250 credits per month, which is more than enough to complete this tutorial and prototype a working solution.

Scavio has a native LangChain package (langchain-scavio), an MCP server, and a plain REST API that works with any HTTP client. This tutorial uses the raw REST API, but you can adapt to your framework of choice.

Start Building

Build an agent that combines live news search with prediction market data. Cross-reference market odds against current events for informed analysis.