apiwren
Use case AI agents

Build a stock research agent with Claude and live market data

A 60-line Python stock research agent: Claude tool use over live Yahoo Finance quotes and price history, so every number it states comes from data, not memory.

By Terrell Louis · Updated

Short answer

Give the model two tools, one for live quotes and one for price history, and let it decide when to call them. The Anthropic Python SDK’s tool runner handles the loop. Data comes from Yahoo Finance Turbo with a RapidAPI key, so it works from servers where yfinance gets rate-limited.

The whole agent

import os
from datetime import datetime, timezone
import anthropic
import requests
from anthropic import beta_tool

HOST = "yahoo-finance-turbo.p.rapidapi.com"
HEADERS = {"X-RapidAPI-Key": os.environ["RAPIDAPI_KEY"], "X-RapidAPI-Host": HOST}


def turbo(path: str, **params) -> dict:
    r = requests.get(f"https://{HOST}{path}", params={"region": "US", **params}, headers=HEADERS, timeout=30)
    r.raise_for_status()
    return r.json()


@beta_tool
def get_quotes(symbols: str) -> str:
    """Latest price, day change, volume and market cap for up to 20 stocks.

    Args:
        symbols: Comma-separated Yahoo Finance symbols, e.g. "NVDA,AMD".
    """
    rows = turbo("/market/v2/get-quotes", symbols=symbols)["quoteResponse"]["result"]
    keep = ("symbol", "shortName", "currency", "regularMarketPrice", "regularMarketChangePercent",
            "regularMarketVolume", "marketCap", "fiftyTwoWeekRange", "regularMarketTime")
    return str([{k: q.get(k) for k in keep} for q in rows])


@beta_tool
def get_price_history(symbol: str, range: str = "6mo", interval: str = "1d") -> str:
    """Daily or weekly closing prices for one stock, as "date,close" lines.

    Args:
        symbol: One Yahoo Finance symbol, e.g. "NVDA".
        range: How far back: 1mo, 6mo, 1y, 5y or max.
        interval: Bar size: 1d, 1wk or 1mo.
    """
    r = turbo("/stock/v3/get-chart", symbol=symbol, range=range, interval=interval)["chart"]["result"][0]
    closes = r["indicators"]["quote"][0]["close"]
    lines = [f"{datetime.fromtimestamp(t, timezone.utc):%Y-%m-%d},{c:.2f}" for t, c in zip(r["timestamp"], closes) if c is not None]
    return "\n".join(lines)


client = anthropic.Anthropic()  # reads ANTHROPIC_API_KEY
runner = client.beta.messages.tool_runner(
    model="claude-opus-5-5",
    max_tokens=16000,
    betas=["server-side-fallback-2026-07-01"],
    fallbacks="default",
    system=(
        "You are a stock research assistant. Get every number from the tools and say which "
        "date it is from. Show your arithmetic. Do not recommend buying or selling."
    ),
    tools=[get_quotes, get_price_history],
    messages=[{"role": "user", "content": "Compare NVDA and AMD over the last 6 months: total return, "
               "largest drop from a peak, and today's move."}],
)
final = runner.until_done()
print("".join(b.text for b in final.content if b.type == "text"))
pip install anthropic requests
export ANTHROPIC_API_KEY=...   # console.anthropic.com
export RAPIDAPI_KEY=...        # Yahoo Finance Turbo on RapidAPI
python stock_agent.py

How it works

  • @beta_tool turns each function’s signature and docstring into a tool definition, so the docstring is what the model reads to decide when to call it.
  • The tool runner sends the question, runs whatever tools Claude asks for, sends back the results and repeats until Claude answers.
  • Tools return small text, not raw API JSON. Six months of daily closes as date,close lines is about 3 KB, which keeps the model’s context and your token bill small.
  • The system prompt makes the agent cite the date of each number and show its arithmetic, and keeps it from giving trade advice.
  • fallbacks="default" lets the API retry on another Claude model if the first one declines a request.

Give it more tools

Each extra tool is one more short function over a Turbo endpoint. Good next ones:

ToolEndpointReturns
Fundamentals/stock/get-fundamentalsIncome statement, balance sheet and cash flow
Valuation/stock/v4/get-statisticsP/E, margins, beta and other key statistics
Earnings/stock/get-earningsEarnings history and estimates
Analysts/stock/get-recommendation-trendRecommendation trend over time
Options/stock/v3/get-optionsOption chains with strikes and expiries
Screener/screeners/get-symbols-by-predefinedDay gainers, most active and other preset screens

The Yahoo Finance API page lists all 37 endpoints. Pass only the fields the agent needs. Smaller tool results make answers cheaper and more accurate.

Questions it handles well

  • “How did the S&P 500 (^GSPC) do this year compared with QQQ?”
  • “Which of AAPL, MSFT and GOOGL is closest to its 52-week high?”
  • “Plot NVDA weekly closes for 5 years and describe the three biggest drawdowns.” (Add a plotting tool or use code execution.)

Not financial advice. Yahoo Finance Turbo is a third-party API, not affiliated with Yahoo.

Yahoo Finance Turbo

37 endpoints, a stated quota, free plan of 500 requests a month.

Get a free key on RapidAPI

FAQ

Why not just ask a chatbot about a stock?
A model’s knowledge stops at its training date, and it will still produce a confident price. With tools, the model fetches today’s quote and history and does arithmetic on real numbers, and you can see which call each number came from.
Is there a Yahoo Finance MCP server?
Yahoo has none, because it has no official API. This page uses Claude tool use instead, which works in your own code with any model call. The same two functions could be wrapped as an MCP server.
How many API requests does one question use?
Usually two to four: one quote call for up to 20 symbols and one history call per symbol. The free plan has 500 requests a month.
Can I use this agent to trade?
This example only reads data and is told not to recommend trades. Nothing on this page is financial advice. If you connect an agent to a broker, keep a human approval step before any order.
Does it work with LangChain or another framework?
Yes. The two tool functions are plain Python that call a REST API. Register them as tools in any framework that supports function calling.