Skip to main content
Welcome back. In this lesson we build a lightweight stock news tracker that:
  • searches the web for the latest updates on a list of companies,
  • summarizes one interesting story for each company,
  • analyzes the sentiment of that summary (positive / neutral / negative),
  • exports the aggregated results into a clean Excel file for further review.
Create a new notebook (or script) and name it Stock News Pro. Save it and make sure your environment contains your OpenAI API key (for example, in a .env file).
Make sure your .env contains a valid API key (for example OPENAI_API_KEY=...). This lesson uses an agents package that provides an Agents SDK and a WebSearchTool to perform live web queries.

Overview

This guide is organized into four clear steps:
  1. Setup and imports
  2. Main logic (single async function that performs search, summarize, classify, and collect)
  3. Running the script (script vs. notebook)
  4. Output format and where files are saved
Follow the sections below to implement the tracker end-to-end.

1 โ€” Setup and imports

Load environment variables and import the core libraries:
# python
from dotenv import load_dotenv
import os

load_dotenv()  # loads environment variables from .env into os.environ
Then import the remaining dependencies:
# python
import asyncio
import pandas as pd
from pathlib import Path

from agents import Agent, Runner, WebSearchTool, trace
Define the list of favorite stocks we want to track:
# python
fav_stocks = ["Google", "Apple", "Nvidia"]

2 โ€” Main logic

Below is a single consolidated async function that:
  1. Creates an Agent with the WebSearchTool.
  2. For each stock:
    • searches the web and requests one recent update in a single sentence,
    • extracts the summary,
    • asks the agent to classify sentiment (positive / neutral / negative),
    • maps the sentiment to an emoji,
    • extracts a source link if available,
    • appends the result to the results list.
  3. Converts the list to a pandas DataFrame and exports it to Excel (both the current working directory and the userโ€™s Downloads folder when possible).
# python
async def main():
    agent = Agent(
        name="Stock News Expert",
        instructions="You are a stock news expert. Review the most recent news on these stocks/companies and provide concise answers.",
        tools=[WebSearchTool(user_location={"type": "approximate", "city": "New York City"})],
    )

    results = []

    with trace("Stock news summary"):
        for stock in fav_stocks:
            query = f"Search the web for news about '{stock}' and give me 1 recent update in a sentence."
            result = await Runner.run(agent, query)
            summary = (result.final_output or "").strip()

            # Ask for sentiment and expect only: positive, neutral, or negative
            sentiment_query = (
                f"What is the sentiment of this sentence? '{summary}' "
                "Answer only with: positive, neutral, or negative."
            )
            sentiment_result = await Runner.run(agent, sentiment_query)
            sentiment = (sentiment_result.final_output or "").strip().lower()

            # Map sentiment to an emoji for quick visual scanning
            sentiment_emoji = {
                "positive": "โœ…",
                "neutral": "๐Ÿ˜",
                "negative": "โŒ",
            }
            sentiment_display = f"{sentiment.capitalize()} {sentiment_emoji.get(sentiment, '')}"

            # Extract a link from sources if present
            link = None
            if hasattr(result, "sources") and result.sources:
                try:
                    # result.sources is often a list of source dicts; attempt to get a URL
                    if isinstance(result.sources, list) and result.sources:
                        link = result.sources[0].get("url")
                    elif isinstance(result.sources, dict):
                        link = result.sources.get("url")
                except Exception:
                    link = None

            results.append({
                "Stock": stock,
                "News": summary,
                "Sentiment": sentiment_display,
                "Link": link
            })

    # Convert results to DataFrame and save to Excel
    df = pd.DataFrame(results)
    filename = "Stock_News_Summary_Pro.xlsx"
    df.to_excel(filename, index=False)
    print(f"News saved to {filename}")

    # Also save a copy to the user's Downloads folder (convenience)
    downloads_path = Path.home() / "Downloads" / filename
    try:
        df.to_excel(downloads_path, index=False)
        print(f"Saved to {downloads_path}")
    except Exception as e:
        print(f"Could not save to Downloads: {e}")
The script performs live web searches using the WebSearchTool. Expect variability in outputs and occasional missing source links. Monitor API usage and rate limits for your API key to avoid unexpected charges.

3 โ€” Running the script

If you are running this as a standalone script, start the async function like this:
# python
if __name__ == "__main__":
    asyncio.run(main())
If you are in a Jupyter notebook, run the coroutine directly with:
# python
await main()

4 โ€” What the output looks like

When the script finishes you will see the Excel files (if both saves succeeded):
LocationFilename
Current working directoryStock_News_Summary_Pro.xlsx
Userโ€™s Downloads folderStock_News_Summary_Pro.xlsx
Each Excel file contains the following columns:
ColumnDescriptionExample
StockThe company name being trackedApple
NewsThe one-sentence recent update returned by the agentApple announces new AI features in iOS.
SentimentSentiment label with emoji (e.g., โ€œPositive โœ…โ€œ)Positive โœ…
LinkSource URL if available (None or blank if not found)https://example.com/news/article
This output is ready for sorting, filtering, or importing into other analytics tools. Thatโ€™s it โ€” you now have a working stock news tracker that searches headlines, summarizes one recent update per company, classifies sentiment, and exports the results to Excel for later analysis. Hope you enjoyed this lesson.

Watch Video

Practice Lab