Tutorial: Stock Analysis Agents
Dec 30, 2025 • 22 min read
In this tutorial, we build a "hedge fund in a box" using CrewAI. Two autonomous agents collaborate: a Senior Research Analyst gathers breaking news and recent financial data, and a Financial Strategist synthesizes that research into a concrete Buy/Hold/Sell recommendation with supporting rationale. This Research → Analyze pipeline is the foundational pattern behind most real-world agentic AI systems.
1. The Agent Team Design
Before writing code, design your agent team by thinking about roles a human team would fill:
Goal: Find all relevant recent information
Tools: Tavily search, news APIs, yfinance
Output: Comprehensive notes with sources
Goal: Synthesize research into recommendation
Tools: No external tools — reasoning only
Output: Structured report: Buy/Hold/Sell with thesis
2. Setup
pip install crewai crewai-tools langchain-community yfinance
# .env
OPENAI_API_KEY=sk-...
TAVILY_API_KEY=tvly-... # Get free key at app.tavily.com3. Define Custom Tools
In addition to Tavily web search, we'll build a custom yfinance tool for pulling live stock data:
from crewai.tools import tool
from langchain_community.tools.tavily_search import TavilySearchResults
import yfinance as yf
import json
# Built-in Tavily search tool
search_tool = TavilySearchResults(max_results=5, search_depth="advanced")
@tool("Stock Data Fetcher")
def get_stock_data(ticker: str) -> str:
"""
Fetches current stock price, P/E ratio, market cap, 52-week range,
and recent earnings data for a given stock ticker symbol.
Use when you need factual financial metrics about a company.
"""
try:
stock = yf.Ticker(ticker.upper())
info = stock.info
hist = stock.history(period="3mo")
return json.dumps({
"ticker": ticker.upper(),
"current_price": info.get("currentPrice", "N/A"),
"market_cap_bn": round(info.get("marketCap", 0) / 1e9, 2),
"pe_ratio": info.get("trailingPE", "N/A"),
"52w_high": info.get("fiftyTwoWeekHigh", "N/A"),
"52w_low": info.get("fiftyTwoWeekLow", "N/A"),
"revenue_growth": info.get("revenueGrowth", "N/A"),
"profit_margins": info.get("profitMargins", "N/A"),
"3mo_price_change_pct": ((hist['Close'].iloc[-1] - hist['Close'].iloc[0]) / hist['Close'].iloc[0] * 100).round(2),
"analyst_recommendation": info.get("recommendationKey", "N/A"),
}, indent=2)
except Exception as e:
return f"Error fetching data for {ticker}: {str(e)}"
@tool("SEC Filings Search")
def search_sec_filings(ticker: str) -> str:
"""Searches recent SEC filings (10-K, 10-Q, 8-K) for the given ticker."""
results = search_tool.invoke(f"{ticker} SEC filing 10-K 10-Q site:sec.gov OR site:edgar.sec.gov")
return str(results)4. Define the Agents
from crewai import Agent
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o", temperature=0.3)
researcher = Agent(
role="Senior Research Analyst",
goal="Conduct comprehensive research on {ticker} stock, finding recent news, earnings, competitive dynamics, and analyst opinions.",
backstory="""You are a veteran Wall Street analyst with 15 years at Goldman Sachs.
You are known for your thorough due diligence and ability to synthesize complex information.
You always cite your sources and indicate information recency.""",
tools=[search_tool, get_stock_data, search_sec_filings],
llm=llm,
verbose=True,
max_iter=5, # Max tool call loops before giving up
memory=True, # Remember context within the task
)
financial_analyst = Agent(
role="Chief Investment Officer",
goal="Write a clear, decisive investment recommendation on {ticker} based on the research provided.",
backstory="""You are a CIO with a proven track record of outperforming the S&P 500.
You are known for your direct, no-nonsense investment theses.
You always provide a concrete recommendation: BUY, HOLD, or SELL with a 12-month price target.""",
tools=[], # This agent reasons only — no external tool access
llm=llm,
verbose=True,
)5. Define the Tasks
from crewai import Task
research_task = Task(
description="""Conduct thorough research on {ticker} stock. Your research must cover:
1. Latest financial metrics: P/E, revenue growth, profit margins, market cap
2. Recent news (last 2 weeks): earnings, product launches, executive changes, regulatory news
3. Competitive landscape: how is {ticker} positioned vs. key competitors?
4. Analyst sentiment: what are major banks saying? Any recent upgrades/downgrades?
5. Technical picture: 52-week range, recent price trend, volume patterns
Use the Stock Data Fetcher for metrics and Tavily search for news and analyst reports.
Present findings in a structured research brief, citing all sources with dates.""",
expected_output="A structured 500-750 word research brief with data, sources, and dates",
agent=researcher,
)
analysis_task = Task(
description="""Based on the research brief provided, write a professional investment recommendation for {ticker}.
Your recommendation must include:
1. Executive summary: BUY / HOLD / SELL in the first sentence
2. 12-month price target with bull/base/bear case scenarios
3. Top 3 reasons for your recommendation (the investment thesis)
4. Risk factors: what could make you wrong?
5. Suggested position sizing for a diversified portfolio
Write in a style suitable for a hedge fund investor letter — clear, direct, data-driven.""",
expected_output="A professional 400-600 word investment recommendation with a clear BUY/HOLD/SELL verdict",
agent=financial_analyst,
context=[research_task], # Receives output from research_task
)6. Assemble and Run the Crew
from crewai import Crew, Process
stock_crew = Crew(
agents=[researcher, financial_analyst],
tasks=[research_task, analysis_task],
process=Process.sequential, # Research THEN analyze (not parallel)
verbose=2, # Full agent thinking logs
memory=True, # Shared memory between agents
)
# Run analysis — can take 2-5 minutes as agents search and reason
result = stock_crew.kickoff(inputs={"ticker": "NVDA"})
print("=" * 60)
print("INVESTMENT RECOMMENDATION")
print("=" * 60)
print(result.raw)
# Save as a report
with open("NVDA_analysis.txt", "w") as f:
f.write(result.raw)7. Extending the System
This two-agent pattern can be extended significantly:
- Add a Risk Manager agent that reviews the recommendation and flags regulatory or ESG risks
- Add a Sector Analyst agent that benchmarks the company against all competitors simultaneously using Parallel CrewAI process
- Add a Portfolio Optimizer agent that considers how the new position affects overall portfolio correlation
- Schedule it with cron to run weekly on your top 20 holdings and email you the summaries
Frequently Asked Questions
Can I trust these AI recommendations for real investment decisions?
No — this system is for research assistance and learning, not financial advice. LLMs can hallucinate financial metrics, misinterpret news significance, and lack access to proprietary data that professional analysts use. Always verify all data points and consult a licensed financial advisor before making investment decisions.
How do I control costs?
The main cost driver is the number of tool calls (each search result consumes tokens). Set max_iter=5 on agents to cap their loop count. Use gpt-4o-mini for the researcher and reserve gpt-4o for the analyst. A typical analysis run costs $0.05-0.20.
Conclusion
The Research → Analyze agent pipeline is the "Hello World" of multi-agent systems, and stock analysis is a perfect domain to learn it — the output is concrete, verifiable, and immediately interesting. Once you understand how to design agent roles, craft effective backstories, and use context passing between tasks, you can apply the same pattern to content creation, technical due diligence, or literature review in any domain.
Continue Reading
Vivek
AI EngineerFull-stack AI engineer with 4+ years building LLM-powered products, autonomous agents, and RAG pipelines. I've shipped AI features to production for startups and worked hands-on with GPT-4o, LangChain, LlamaIndex, and the Vercel AI SDK. I started OpnCrafter to share everything I wish I had when learning — no fluff, just working code and real-world context.