Building a Multi-Agent System to Identify Short-Term Trading Opportunities with Agno's Agentic Framework
A technical deep dive into building an intelligent short-term trading analysis system with Agno's multi-agent framework. Built with the latest Agno V2 framework.
Before diving into the architecture, it's worth understanding what makes an agent-based approach fundamentally different from traditional programming—and why Agno was the right framework for this application.
In traditional software, you write code that follows a fixed execution path. With agents, the language model decides the execution flow: when to think, when to call tools, when to respond. This dynamic decision-making is what enables intelligent orchestration of complex trading analysis.
Consider analyzing a stock: a fixed workflow always calls the same tools in the same order. An agent evaluates the query, decides which analysis is needed, executes only relevant tools, and adapts based on what it discovers. When the Finance Agent finds no opportunities, the agent workflow skips unnecessary downstream analysis. This intelligence is built into the architecture, not hardcoded.
Building an Agent: Start Simple, Add Complexity
At minimum, an agent needs three components:
- Model - Controls execution flow (Claude Sonnet 4.5 for our Team Leader, GPT-4.1 for specialized agents)
- Tools - Functions the agent can call (125+ specialized tools across our 6 agents)
- Instructions - Programs agent behavior and tool usage patterns
These three are enough to build functional agents. But for comprehensive trading intelligence, we layer in advanced capabilities:
- Storage - PostgreSQL database persistence makes agents stateful, enabling multi-turn conversations where follow-up questions maintain context
- Memory - Agents access previous interactions within a session via
share_member_interactions=True, allowing the Technical Agent to see what the Finance Agent discovered - Reasoning -
ReasoningTools(think(),analyze()) let agents plan before acting and evaluate results before responding
Our system implements all six capabilities across specialized agents working in coordination.
What attracted us to Agno was its refusal to add unnecessary abstraction layers. Agents inherit from a single base class with transparent implementation. When debugging a trading recommendation, you can trace exactly what happened without navigating nested framework magic. For financial systems requiring audit trails and regulatory compliance, this transparency isn't optional.
Automatic Tool Discovery: Write Python functions with type hints and docstrings—Agno automatically converts them into agent-callable tools. No manual schema definitions. This let us rapidly build 125+ specialized tools without framework overhead.
Reasoning Capabilities:
The ReasoningTools (think(), analyze()) let agents explicitly plan their approach. The Team Leader uses these to decide which agents to activate, in what order, and whether to skip phases based on results. This isn't just calling tools—it's intelligent orchestration.
Coordinate Mode Orchestration: Agno supports multiple team execution patterns. We use coordinate mode where the Team Leader sequentially delegates to specialized agents, maintaining shared context. Each agent sees all previous interactions, enabling true collaborative intelligence rather than isolated analysis.
Storage & Memory:
PostgreSQL database persistence (Storage) makes agents stateful—model APIs are inherently stateless, but Storage enables multi-turn conversations within a session. Combined with Memory (share_member_interactions=True), agents see all previous interactions, enabling follow-up questions like "What about earnings timing?" where the system knows you're still discussing the same stock.
Note: While Agno supports Knowledge (vector databases for RAG/Agentic Search), we don't use it. Trading intelligence requires real-time data, not historical document search. Our 125+ tools connect directly to live APIs (YFinance, Federal Reserve, FDA, SEC) rather than pre-indexed content.
Streaming Architecture: Built-in async streaming means the UI updates in real-time as agents work. Users see tool executions, agent reasoning, and progress—not a black box that eventually returns an answer.
We started simple: one agent, basic financial data tools, direct stock analysis. Once that worked, we added technical analysis. Then sentiment. Then risk optimization. Then multi-agent coordination. Each layer proved its value before adding complexity.
This mirrors Agno's design philosophy: start with model + tools + instructions. Add sophistication only when needed. The result is a system with 6 agents and 125+ tools that remains maintainable because complexity was earned, not assumed.
The Challenge:
Analyzing a stock for short-term trading requires synthesizing data from multiple domains: technical indicators, fundamentals, insider trading, dark pool activity, social sentiment, news catalysts, and macro-economic conditions. Traditional approaches either automate individual pieces or require manual synthesis across all dimensions.
The System:
A multi-agent intelligence system using the Agno framework that orchestrates 6 specialized agents to identify the best short-term trading opportunities. The system analyzes stocks across multiple dimensions—fundamentals, technical indicators, sentiment, news, and risk—through coordinate mode execution with shared context, then synthesizes findings into actionable insights.
In designing this project, the challenge wasn't just building individual tools—it was getting them to work together intelligently. This article walks through the technical architecture, the decisions that shaped it, and how Agno's framework made this level of coordination possible.
This is not a pure quantitative trading system. It's a hybrid intelligence platform that combines quantitative methods with alternative data sources, sentiment analysis, and fundamental research—orchestrated through human decision-making rather than automated execution.
1. Quantitative Intelligence (Mathematical/Statistical)
The system employs sophisticated quantitative tools:
- Technical Analysis: RSI, MACD, Bollinger Bands, moving averages, volatility models
- Machine Learning Ensemble: Multi-model voting (RandomForest + XGBoost + SVM + LSTM) with probability-based confidence scoring and walk-forward validated training
- Risk Management: Position sizing formulas, ATR-based stop-loss calculations, edge score optimization
But quantitative analysis is just one dimension—not the entire system.
2. Alternative Data Intelligence (Non-Quantitative)
What separates this from pure quant systems:
- Congressional Trading: Tracking government insider trades (not available in traditional quant models)
- Dark Pool Activity: Institutional smart money flow detection
- Insider Trading: Corporate insider buy/sell signals
- Short Interest Dynamics: Squeeze potential identification
This alternative data provides signals that mathematical models alone cannot capture.
3. Sentiment Intelligence (Qualitative)
Real-time social and news sentiment:
- Twitter/X Analysis: Social momentum and retail trader sentiment
- Reddit Communities: Trading discussion sentiment across financial subreddits
- News Sentiment: Breaking news impact and market buzz
- Hype Detection: Viral momentum identification for explosive opportunities
Sentiment data reflects human psychology and market emotion—factors that pure quantitative systems deliberately exclude.
4. Fundamental & Event Intelligence (Qualitative)
Critical Timing Advantage: The system monitors 9 comprehensive event types with 1-5 day advance detection, providing strategic positioning before events are priced in:
- Federal Reserve Events: Policy meetings, rate decisions, economic speeches (macro impact)
- Earnings Intelligence: Company earnings releases, guidance updates, analyst days
- Regulatory Events: FDA drug approvals, clinical trial results, SEC enforcement actions
- Political Events: Policy announcements, regulatory changes, government insider trades
- Economic Data: Jobs reports, inflation data, GDP releases, consumer sentiment
- Corporate Catalysts: M&A announcements, product launches, management changes
- Geopolitical Events: Trade developments, international conflicts, sanctions
- Options Expiration: Market-moving technical events and volatility patterns
- Sector Catalysts: Industry-specific events affecting multiple stocks
Why Event Intelligence Matters for Short-Term Trading:
- 📅 Earnings in 2 days? → Risk Optimizer adjusts position sizing and recommends exit timing
- 🏛️ Fed meeting tomorrow? → System warns of macro volatility and suggests wait-and-see
- 💊 FDA approval expected? → Biotech opportunity with catalyst-driven upside potential
- 📊 Jobs report Friday? → Timing adjustments to avoid pre-announcement volatility
This isn't reactive news monitoring—it's predictive event intelligence with ML-based impact scoring that adjusts trading strategy based on upcoming catalysts.
Here's how the system works from start to finish:
┌─────────────────────────────────────────────────────────────────────┐
│ 👤 USER INTERACTION │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ User asks: "Is $AAPL a good short-term buy opportunity?" │
│ Selects Trading Profile: 🔴 Aggressive │
│ │
└────────────────────────────────┬────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 🧠 TEAM LEADER (Claude Sonnet 4.5) │
│ Coordinate Mode Orchestration │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 1️⃣ Receives query + Aggressive profile instructions │
│ 2️⃣ Decides which agents to activate and in what order │
│ 3️⃣ Uses ReasoningTools to think() and analyze() at each step │
│ │
└────────────────────────────────┬────────────────────────────────────┘
│
┌────────────────────┴───────────────────┐
│ SEQUENTIAL AGENT EXECUTION │
│ (Each agent sees previous outputs) │
└────────────────────┬───────────────────┘
│
▼
╔════════════════════════════════════════════════════╗
║ PHASE 0: Sector Mapping (Conditional) ║
╠════════════════════════════════════════════════════╣
║ 🗺️ Sector Mapper Agent (GPT-4.1) ║
║ ├─ Activates IF user specifies sector ║
║ ├─ Maps user sector terms to standard tickers ║
║ └─ Output: Sector context for screening ║
╚════════════════════════════════════════════════════╝
│
▼
╔════════════════════════════════════════════════════╗
║ PHASE 1: Financial Intelligence (Always Runs) ║
╠════════════════════════════════════════════════════╣
║ 💰 Finance Agent (GPT-4.1) - 98 Tools ║
║ ├─ 🎯 Price, fundamentals, insider trades ║
║ ├─ 🌊 Dark pool activity, short interest ║
║ ├─ 🏛️ Congressional trades, analyst actions ║
║ ├─ 📅 Event Intelligence (9 types, 1-5 day ahead) ║
║ ├─ 🚨 Market warnings, macro conditions ║
║ └─ Output: Trading opportunities + risk factors ║
╚════════════════════════════════════════════════════╝
│
Team Leader checks: Did Finance find opportunities?
│
┌────────────┴────────────┐
│ │
NO YES
│ │
▼ ▼
Skip remaining agents Continue workflow
Return "No opportunities"
│
▼
╔════════════════════════════════════════════════════╗
║ PHASE 2: Technical Validation ║
╠════════════════════════════════════════════════════╣
║ 📈 Technical Agent (GPT-4.1) - 22 Tools ║
║ ├─ Technical indicators (RSI, MACD, Bollinger) ║
║ ├─ ML ensemble (RandomForest + XGBoost + LSTM) ║
║ ├─ Multi-timeframe analysis (Daily/Hourly/5-min) ║
║ ├─ Support/resistance levels ║
║ └─ Output: Entry/exit timing + ML confidence ║
╚════════════════════════════════════════════════════╝
│
▼
╔═══════════════════════════════════════════════════════════╗
║ PHASE 3: Parallel Intelligence Gathering ║
╠═══════════════════════════════════════════════════════════╣
║ ║
║ 🌐 Web Agent (GPT-4.1) 📱 Sentiment Agent ║
║ ├─ Breaking news ├─ Twitter/X sentiment ║
║ ├─ Catalyst research ├─ Reddit WSB tracking ║
║ └─ Market context └─ Hype detection ║
║ ║
║ Output: News catalysts + Social momentum indicators ║
╚═══════════════════════════════════════════════════════════╝
│
▼
╔════════════════════════════════════════════════════╗
║ PHASE 4: Risk Optimization ║
╠════════════════════════════════════════════════════╣
║ ⚡ Risk Optimizer Agent (GPT-4.1) - 5 Tools ║
║ ├─ Enhanced edge scoring (51% → 57% win rate) ║
║ ├─ Optimal timeframe (1-3 day catalyst timing) ║
║ ├─ Position sizing (max 2% per trade) ║
║ ├─ Stop-loss levels (ATR-based, max -3%) ║
║ └─ Profit targets (resistance-based) ║
║ ║
║ Output: Conservative institutional recommendations ║
╚════════════════════════════════════════════════════╝
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 🧠 TEAM LEADER FINAL SYNTHESIS │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 1️⃣ Reviews all agent outputs via shared context │
│ 2️⃣ Uses ReasoningTools to analyze() contradictions │
│ 3️⃣ Applies Aggressive profile instructions: │
│ • Multiplies Risk Optimizer's position sizing by 2-3x │
│ • Widens stop-loss from -3% to -5% to -8% │
│ • Embraces catalyst risk (earnings in 2 days = opportunity) │
│ 4️⃣ Synthesizes final recommendation with reasoning chain │
│ 5️⃣ Saves complete analysis to timestamped .md file │
│ │
└────────────────────────────────┬────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 📊 STREAMLIT UI RESPONSE │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ Real-time streaming display shows: │
│ │
│ ✅ Phase 1: Finance Agent │
│ └─ Executed 23 tools (dark pool, insider trades, events...) │
│ │
│ ✅ Phase 2: Technical Agent │
│ └─ Executed 15 tools (RSI, ML ensemble, multi-timeframe...) │
│ │
│ ✅ Phase 3: Web + Sentiment Agents (Parallel) │
│ └─ Web: 4 tools | Sentiment: 6 tools │
│ │
│ ✅ Phase 4: Risk Optimizer │
│ └─ Executed 5 tools (edge score, position sizing, stops...) │
│ │
│ 🎯 FINAL RECOMMENDATION: │
│ │
│ 🚀 STRONG BUY - $AAPL │
│ • Entry: $185.50 │
│ • Position: 4-6% (Aggressive profile - 2-3x Risk Optimizer) │
│ • Stop-Loss: -5% to -8% (wide for catalyst volatility) │
│ • Target: $195.00 (+5.1% gain, 2-day hold) │
│ • Catalyst: Earnings beat + insider buying + bullish momentum │
│ • Exit: Before market close Day 2 or hold through earnings │
│ │
│ Reasoning: Strong fundamentals (Finance), confirmed breakout │
│ (Technical), extreme bullish sentiment (Sentiment), positive news │
│ catalyst (Web). Risk Optimizer's conservative 2% position adjusted │
│ to 4-6% for Aggressive profile. Earnings in 2 days = opportunity. │
│ │
│ 📄 Full analysis saved to: AAPL_2025-01-07_14-23-45_analysis.md │
│ │
└─────────────────────────────────────────────────────────────────────┘
│
▼
👤 User makes decision
(System provides intelligence,
human makes final trading call)
Key Workflow Characteristics:
- Coordinate Mode: Team Leader orchestrates sequential execution with conditional logic
- Shared Context: Each agent sees all previous agent outputs via
share_member_interactions=True - Reasoning-First: Every agent uses
think()→ [tool calls] →analyze()→ final answer - Adaptive Execution: Phases can be skipped if Team Leader determines they're unnecessary
- Profile-Aware: Team Leader applies risk profile instructions to transform recommendations
- Real-Time Streaming: Users watch analysis unfold live, not a black box
- Audit Trail: Complete analysis automatically saved for review and compliance
Critical distinction: The system provides intelligence and recommendations but requires human decision-making.
- ❌ NOT algorithmic execution (no auto-buy/sell)
- ❌ NOT rule-based trading (no "if RSI < 30, execute buy")
- ❌ NOT black-box automation (human interprets results)
- ✅ Decision support tool (human makes final call)
- ✅ Adaptive to risk profiles (Aggressive/Moderate/Conservative)
- ✅ Contextual recommendations (considers multiple data dimensions)
The critical insight: Agno's extensibility enables seamless integration of diverse data sources—quantitative models, alternative data APIs, sentiment tools, and fundamental research—within a unified intelligence framework.
Traditional approach requires:
- Separate systems for each data dimension (quant models, sentiment APIs, fundamental databases)
- Manual integration and orchestration across platforms
- Complex schema definitions for each data source
- Custom serialization for disparate data types
With Agno's automatic function introspection:
from agno.tools import Toolkit
# QUANTITATIVE TOOLKIT
class MLTradingTools(Toolkit):
def predict_price_movement(self, ticker: str, rsi: float, macd: float) -> Dict:
"""ML prediction using RandomForest + XGBoost ensemble."""
# Ensemble prediction with 4 models
return {"buy_probability": 0.73, "confidence": 0.82}
# ALTERNATIVE DATA TOOLKIT
class CongressionalTradingTools(Toolkit):
def track_congressional_trades(self, ticker: str, days: int) -> Dict:
"""Track recent government insider trades."""
# Query Quiver Quantitative API
return {"recent_trades": [...], "sentiment": "bullish"}
# SENTIMENT TOOLKIT
class TwitterSentimentTools(Toolkit):
def analyze_twitter_sentiment(self, ticker: str, hours: int) -> Dict:
"""Analyze Twitter sentiment using XTools API."""
# Real-time social sentiment
return {"sentiment_score": 0.65, "tweet_volume": 1250}
# Agno automatically:
# 1. Extracts function signatures from all three toolkits
# 2. Generates JSON schemas for diverse parameter types
# 3. Handles complex return types (ML probabilities, API responses, sentiment scores)
# 4. Coordinates tool execution across agentsThe agent can now call:
# Quantitative analysis:
ml_result = predict_price_movement(ticker="AAPL", rsi=35.2, macd=-0.48)
# Alternative data:
congressional = track_congressional_trades(ticker="AAPL", days=30)
# Sentiment intelligence:
sentiment = analyze_twitter_sentiment(ticker="AAPL", hours=48)
# All results synthesized by Team Leader for human decisionWhat makes this powerful:
The LLM doesn't need to understand:
- RandomForest hyperparameters (quantitative)
- Quiver API authentication (alternative data)
- Twitter API rate limits (sentiment)
- Different data formats and schemas
Agno abstracts the complexity while preserving the intelligence from each dimension.
Pure quant systems (Renaissance, Two Sigma, D.E. Shaw):
- ✅ Excellent at pattern recognition in price/volume data
- ✅ High-frequency execution at millisecond scale
- ❌ Miss alternative data signals (congressional trades, dark pool flows)
- ❌ Ignore sentiment and social momentum
- ❌ Require massive infrastructure for speed advantage
This hybrid system:
- ✅ Combines quantitative rigor with alternative intelligence
- ✅ Captures sentiment shifts before they appear in price data
- ✅ Identifies catalyst-driven opportunities (earnings, FDA, insider trades)
- ✅ Adapts to human risk tolerance and trading style
- ✅ Accessible to individual traders (not just institutions)
Example: A pure quant system might identify SMCI as oversold based on RSI/MACD. This system adds:
- Congressional trades showing recent government buying
- Dark pool accumulation indicating institutional interest
- Twitter sentiment detecting retail momentum shift
- Upcoming earnings catalyst for timing optimization
The result: Higher-quality signals through multi-dimensional analysis.
With Agno's custom tool extensibility:
Diverse data sources become simple Python functions that agents call autonomously. The framework handles:
- Schema generation from mixed data types (floats, strings, arrays, objects)
- Type conversion for statistical models (numpy), APIs (JSON), and databases (SQL)
- State management for ML models, API connections, and database sessions
- Result serialization for probabilities, sentiment scores, and fundamental metrics
This makes building multi-dimensional intelligence systems as straightforward as building single-purpose quantitative models—but with dramatically higher signal quality through data fusion.
Short-term trading (1-3 day timeframes) requires analyzing multiple data dimensions simultaneously:
- Financial Intelligence: Price action, earnings, insider trades, institutional flows, analyst revisions
- Technical Analysis: Support/resistance, indicators, multi-timeframe alignment, ML enhancement
- Market Intelligence: News, catalysts, regulatory events, sector rotation
- Sentiment Analysis: Social media momentum, Reddit activity, Twitter trends
- Risk Management: Position sizing, stop-loss levels, profit targets, edge scoring
Traditional approaches either:
- Automate individual pieces (charting software, news aggregators) but require manual synthesis
- Use single-agent systems that lack domain specialization and struggle with complex reasoning
The Gap: No framework for building multi-agent systems where specialized agents can reason independently, share context, and execute in a coordinated workflow with dependencies.
Why Agno: The Agno framework for building multi-agent systems provides built-in reasoning capabilities, coordinate mode orchestration, shared context management, and advanced features (hooks, session persistence, streaming) that make intelligent opportunity identification possible.
Before diving into the architecture, let's understand the foundation that makes this level of intelligence possible. Agno is a framework for building agents with built-in memory, knowledge, session management, and reasoning capabilities.
The key word here is reasoning. This isn't just another tool-calling framework—it's designed from the ground up to enable AI agents that can think, analyze, and make intelligent decisions.
Most AI frameworks treat agents as simple orchestrators: call a tool, get a result, format output, done. Agno takes a fundamentally different approach by making reasoning a first-class citizen.
Here's a simple example of analyzing a stock:
Traditional Tool-Calling Approach:
# Simple tool orchestration
price = get_stock_price("AAPL")
rsi = get_rsi("AAPL")
if rsi < 30:
return "BUY - Stock is oversold"Agno's Reasoning Approach:
from agno.agent import Agent
from agno.tools.reasoning import ReasoningTools
agent = Agent(
name="Finance Analyst",
tools=[ReasoningTools(), YFinanceTools()],
instructions=[
"Use think() to reason through market conditions",
"Use analyze() to synthesize multiple data points",
"Provide reasoned recommendations, not mechanical signals"
]
)
# The agent doesn't just call tools—it reasons
response = agent.run("Should I buy AAPL right now?")What the agent does internally:
- Thinks: "Need to understand why AAPL might be a buy opportunity"
- Calls tools: Gets price, RSI, volume, insider trades, earnings date
- Analyzes: "RSI is oversold, but insiders sold last week, earnings in 2 days"
- Reasons: "Oversold signal is valid, but insider selling + earnings risk = wait"
- Synthesizes: "WAIT - Despite oversold RSI, insider selling and earnings proximity suggest caution"
This is the difference between a tool-calling bot and an intelligent agent.
1. Built-In Reasoning Tools
Agno provides native reasoning capabilities through ReasoningTools. Here's how it integrates into every agent:
from agno.tools.reasoning import ReasoningTools
from agno.agent import Agent
from agno.models.openai import OpenAIChat
# Example: Technical Analysis Agent with Reasoning
technical_agent = Agent(
name="Technical Analysis Agent",
role="Technical signals and strategy validation specialist",
id="technical-analysis-agent",
model=OpenAIChat(id="gpt-4.1"),
# Reasoning tools FIRST - enables intelligent analysis
tools=[
ReasoningTools(
enable_think=True, # Step-by-step reasoning
enable_analyze=True, # Multi-point synthesis
add_instructions=True, # Add reasoning guidance
add_few_shot=True # Include examples
),
TechnicalAnalysisTools(),
MultiTimeframeAnalysisTools(),
MLSignalEnhancementTools(),
InstitutionalMLTradingTools(),
PlotlyVisualizationTools()
],
# Instructions emphasize reasoning
instructions=[
"Use think() to reason through technical patterns",
"Use analyze() to synthesize signals across timeframes",
"Provide reasoned entry/exit levels, not just indicators"
],
# Enable memory for learning
add_history_to_context=True,
num_history_runs=3,
markdown=True,
add_datetime_to_context=True
)ReasoningTools provides two critical functions that enable structured, multi-step reasoning:
1. think() - Internal Reasoning Scratchpad
- Called BEFORE making any tool calls or decisions
- Agent breaks down complex problems step-by-step
- Parameters:
title,thought,action,confidence - Stores reasoning chain in session_state (agent builds on previous thoughts)
- Internal only - not shown to user
2. analyze() - Result Evaluation & Synthesis
- Called AFTER tool calls to evaluate outcomes
- Agent assesses: Is this result sufficient? Is more data needed?
- Parameters:
title,result,analysis,next_action,confidence next_action: "continue" (more reasoning needed), "validate" (seek confirmation), or "final_answer" (ready to respond)- Internal only - user sees only the final synthesized answer
Agno's Enforced Workflow (from source code):
You must ALWAYS think before making tool calls or generating a response.
Flow: Think → [Parallel Tool Calls] → [Analyze] → ... → Final Answer
Example:
1. think(title="Analyze signal", thought="RSI oversold at 35, but need context...")
2. [Parallel tool calls: check_volume(), check_4h_chart(), check_support_resistance()]
↑ These are DOMAIN tools (YFinance, Technical Analysis, etc.)
↑ Called IN PARALLEL for efficiency - all execute simultaneously
3. analyze(title="Evaluate results", analysis="Volume weak + resistance nearby", next_action="final_answer")
4. Respond to user with synthesized conclusion
What "Parallel Tool Calls" Means:
After the agent uses think() to reason about what it needs to check, it can call multiple domain-specific tools simultaneously rather than waiting for each one sequentially.
In Trading Context:
# Agent's reasoning tools (ReasoningTools)
think() → Plans what data is needed
↓
# Agent's domain tools (YFinanceTools, TechnicalAnalysisTools, etc.)
Call IN PARALLEL:
- get_current_price("AAPL") # YFinance tool
- get_volume_profile("AAPL") # YFinance tool
- check_rsi_4h("AAPL") # Technical tool
- check_support_resistance("AAPL") # Technical tool
↓
All results return together (not sequentially)
↓
analyze() → Evaluates all results
↓
Final AnswerWhy This Matters:
- ❌ Sequential: 4 tools × 2 seconds each = 8 seconds
- ✅ Parallel: 4 tools simultaneously = 2 seconds
Verified from Agno source: "Make multiple tool calls in parallel: After a think step, you can make multiple tool calls in parallel."
Here's the difference in practice:
Without ReasoningTools (Direct tool calling):
Agent sees: RSI=35 (oversold), MACD=bullish
Agent responds immediately: "BUY signal. RSI is oversold at 35 and MACD is bullish."
With ReasoningTools (Structured reasoning):
Internal Process (user doesn't see this):
Step 1. think(
title="Evaluate RSI signal",
thought="RSI at 35 is technically oversold, but need to check context before recommending entry",
action="Check volume profile and multi-timeframe confirmation",
confidence=0.7
)
Step 2. [PARALLEL TOOL CALLS - All execute simultaneously]
├─ Tool Call 1: get_volume_profile("AAPL") → YFinanceTools
├─ Tool Call 2: check_rsi_4h("AAPL") → TechnicalAnalysisTools
├─ Tool Call 3: check_support_resistance("AAPL") → TechnicalAnalysisTools
└─ Tool Call 4: get_macd_signal("AAPL") → TechnicalAnalysisTools
Results (all returned together):
• Volume: -15% below 20-day average (declining)
• RSI 4H: 35 (oversold)
• Resistance: $187 (0.8% away from current $185.50)
• MACD: Bullish crossover (fresh signal)
Step 3. analyze(
title="Volume analysis",
result="Volume declining -15% below 20-day average",
analysis="Weak volume contradicts oversold signal. This suggests lack of buying pressure despite low RSI.",
next_action="continue",
confidence=0.8
)
Step 4. think(
title="Multi-timeframe synthesis",
thought="4H chart shows resistance at $187, current price $185.50. Proximity to resistance adds risk.",
action="Combine all factors for final recommendation",
confidence=0.85
)
Step 5. analyze(
title="Final risk assessment",
result="Oversold RSI + Bullish MACD BUT weak volume + nearby resistance",
analysis="Despite bullish indicators, weak volume and resistance proximity create unfavorable risk/reward. Better to wait for volume confirmation or pullback to stronger support.",
next_action="final_answer",
confidence=0.9
)
Agent's Final Response to User:
"WAIT for better entry. While RSI shows oversold at 35 and MACD is bullish, declining volume (-15% below average) suggests weak buying pressure. Additionally, 4H resistance at $187 is only 0.8% away, creating unfavorable risk/reward. Recommend waiting for either: (1) volume surge confirming buying interest, or (2) pullback to $182 support level."
Key Insight: Step 2 shows the power of parallel tool execution—instead of waiting 8 seconds (4 tools × 2s each), all 4 domain tools execute simultaneously in ~2 seconds, returning results together for the agent to analyze.
The Intelligence Difference:
| Aspect | Without ReasoningTools | With ReasoningTools |
|---|---|---|
| Decision Process | Immediate, reactive | Deliberate, multi-step |
| Context Analysis | Indicator values only | Cross-validates multiple factors |
| Risk Assessment | Missing | Explicit evaluation of contradictions |
| Confidence | No tracking | Tracks confidence at each step |
| Reasoning Chain | None | Cumulative (each thought builds on previous) |
| Final Answer | Mechanical signal | Nuanced synthesis with rationale |
ReasoningTools transforms agents from mechanical signal generators into intelligent analysts that think through problems, validate assumptions, and synthesize contradictions before making recommendations.
2. Multi-Agent Teams with Shared Intelligence
Agno's Team class enables sophisticated multi-agent orchestration:
from agno.team import Team
team = Team(
name="Trading Intelligence Team",
agents=[finance_agent, technical_agent, sentiment_agent],
model=Claude(id="claude-sonnet-4-5"),
# Coordinate mode: agents execute sequentially with dependencies
delegate_task_to_all_members=False,
respond_directly=False,
# Share context between agents
share_member_interactions=True,
# Team leader reasons across all agent outputs
tools=[ReasoningTools()],
instructions=["Synthesize findings from all agents with reasoning"]
)This architecture enables:
- Sequential execution with dependency management (Phase 1 → Phase 2 → Phase 3)
- Shared context so each agent builds on previous findings
- Team-level reasoning where the leader synthesizes across all perspectives
3. Session Persistence for Context
Agents maintain conversation history within the current session:
from agno.db.postgres import PostgresDb
agent = Agent(
name="Finance Agent",
db=PostgresDb(db_url=DATABASE_URL),
# Maintain conversation history in current session
add_history_to_context=True,
num_history_runs=3,
# Enable runtime state management
enable_agentic_state=True
)This means within a single session, the agent can reference:
- Previous questions and responses from the current conversation
- Context from earlier in the same session
- Tool results from prior queries in this session
Practical Example of Within-Session Context:
Scenario: Multiple queries in the same session
Session Start (Session ID: abc-123)
User Query 1: "Is $AAPL a good short-term buy?"
→ Finance Agent analyzes AAPL, executes 98 tools from its Toolkits, finds bullish signals
→ Response: "BUY $AAPL - Strong momentum, earnings beat, target $185"
User Query 2: "What about $MSFT compared to that?"
→ Agent has context from Query 1:
✅ Knows "that" refers to $AAPL
✅ Remembers the focus on short-term trading opportunities
✅ Can compare $MSFT to $AAPL's analysis
→ Response: "MSFT shows similar momentum but lower volatility.
Compared to AAPL's 8% upside, MSFT offers 5% upside with less risk."
User Query 3: "Which one has better risk/reward?"
→ Agent has full context from Queries 1 & 2:
✅ Knows the comparison is between $AAPL vs $MSFT
✅ Has both analyses in conversation history
✅ Can synthesize across both
→ Response: "AAPL has better risk/reward (2.8:1 vs MSFT 2.1:1)
for 1-3 day trades based on current momentum."
Session End
What happens when you start a NEW session:
New Session Start (Session ID: xyz-789)
User Query: "Which one has better risk/reward?"
→ Agent has NO context:
❌ Doesn't know what "which one" refers to
❌ No memory of AAPL or MSFT analyses
❌ Conversation history from previous session is NOT available
→ Response: "Need more context. Which stocks are you comparing?"
Within-session context enables natural conversation flow (follow-up questions, comparisons, clarifications) but each new session starts completely fresh to ensure objective analysis based on current market conditions, not yesterday's or last week's analysis.
Note: The system does NOT maintain memory across sessions—each new session starts fresh to ensure objective, contamination-free analysis based solely on current market conditions
4. Data Validation with Hooks
Agno's hook system enables data quality validation—critical for trading. Here's our actual implementation:
def validate_critical_data_sources_before_analysis(run_input: Any) -> None:
"""Pre-hook: Validate all critical data sources before analysis begins.
Agno automatically passes 'run_input' (TeamRunInput) to this hook.
Hook executes BEFORE Phase 0, taking ~5-10 seconds to validate all sources.
"""
validation_errors = []
# Test YFinance API with SPY
try:
spy = yf.Ticker("SPY")
current_price = spy.info.get('currentPrice')
if not current_price:
validation_errors.append("❌ YFinance API: Cannot retrieve stock prices")
except Exception as e:
validation_errors.append(f"❌ YFinance API: {str(e)}")
# Test BLS API for economic data
try:
response = requests.get("https://api.bls.gov/publicAPI/v2/timeseries/data/...", timeout=10)
if response.status_code != 200:
validation_errors.append("❌ BLS API: Not accessible")
except Exception as e:
validation_errors.append(f"❌ BLS API: {str(e)}")
# Fail fast if critical data unavailable
if validation_errors:
raise ValueError("Cannot proceed - critical data sources unavailable")
def generate_comprehensive_data_quality_report(run_output: Any) -> None:
"""Post-hook: Generate data quality report after all phases complete.
Agno automatically passes 'run_output' (TeamRunOutput) to this hook.
Hook executes AFTER Phase 5, providing holistic quality assessment.
"""
quality_metrics = {
"yfinance_success_rate": "98%",
"bls_data_freshness": "real-time",
"tool_execution_rate": "100%"
}
logger.info(f"📊 Data Quality Report: {quality_metrics}")
# Apply to team
team = Team(
agents=[...],
pre_hooks=[validate_critical_data_sources_before_analysis],
post_hooks=[generate_comprehensive_data_quality_report]
)Agno's Flexible Hook System:
Agno prepares multiple possible arguments and uses intelligent filtering to pass ONLY what your hook signature requests:
Available for pre_hooks:
run_input: TeamRunInput (what user asked)team: Team object (access to configuration)session: TeamSession (current session data)user_id: Optional[str]debug_mode: Optional[bool]
Available for post_hooks:
run_output: TeamRunOutput (analysis results)team: Team objectsession: TeamSessionuser_id: Optional[str]debug_mode: Optional[bool]
You only include what you need:
# Minimal (our approach) - clean and focused
def pre_hook(run_input: Any) -> None:
# Validate input
pass
# With team access - if you need configuration
def pre_hook(run_input: Any, team: Any) -> None:
# Access team.model, team.debug_mode, etc.
pass
# Full access - if you need session data
def pre_hook(run_input: Any, team: Any, session: Any) -> None:
# Access session history
passWhy This Matters:
-
Pre-hooks (fail-fast): If YFinance or BLS APIs are down, the system fails immediately with a clear error rather than proceeding with incomplete data. This prevents trading decisions based on stale or missing information.
-
Post-hooks (quality reporting): Provides comprehensive data quality assessment after analysis completes, helping users evaluate recommendation reliability.
-
No performance penalty: Hooks don't slow down the main workflow—pre-hook validation (5-10s) is upfront, post-hook reporting is after user already has results.
With these intelligence capabilities, the system enables:
Each Agent Reasons Through Its Domain:
# Finance Agent reasons through opportunities
finance_agent = Agent(
name="Finance Agent",
tools=[ReasoningTools(), YFinanceTools(), DarkPoolTools()],
instructions=[
"Think through why a stock might be a trading opportunity",
"Analyze insider trading, dark pool activity, and catalysts",
"Reason through risk factors before recommending"
]
)
# Technical Agent reasons through entry/exit timing
technical_agent = Agent(
name="Technical Agent",
tools=[ReasoningTools(), TechnicalAnalysisTools(), MLTools()],
instructions=[
"Think through optimal entry and exit levels",
"Analyze multiple timeframes for confirmation",
"Reason through strategy confidence before recommending"
]
)The Team Leader Synthesizes with Intelligence:
team = Team(
name="Trading Intelligence Team",
agents=[sector_mapper, finance_agent, technical_agent,
web_agent, sentiment_agent, risk_optimizer],
tools=[ReasoningTools()],
instructions=[
"Think through how all agent findings connect",
"Analyze for consistency and contradictions",
"Reason through final recommendation with timing",
"Synthesize into actionable trading plan"
]
)Here's what happens when you ask: "Is $PATH a good short-term buy?"
Phase 1 - Finance Agent (Reasoning):
- Thinks: "Need to understand PATH's current financial health and catalysts"
- Calls 20+ tools: Price, earnings, insider trades, dark pool, congressional trades
- Analyzes: "Strong fundamentals, but insiders selling, earnings in 3 days"
- Reasons: "Opportunity exists but timing is risky due to earnings proximity"
Phase 2 - Technical Agent (Reasoning):
- Thinks: "Need to validate entry timing and risk levels"
- Calls 15+ tools: Technical indicators, ML signals, multi-timeframe analysis
- Analyzes: "Bullish breakout confirmed, but overbought on daily timeframe"
- Reasons: "Entry is valid on 4H timeframe, but need tight stop-loss"
Phase 3 - Sentiment Agent (Reasoning):
- Thinks: "Need to gauge market sentiment and momentum"
- Calls 8+ tools: Twitter sentiment, Reddit analysis, news search
- Analyzes: "Extremely bullish social sentiment, potential for momentum"
- Reasons: "Sentiment supports the trade but watch for exhaustion"
Phase 4 - Risk Optimizer (Reasoning):
- Thinks: "Need to size position appropriately for 1-3 day timeframe"
- Calls 5 tools: Edge scoring, position sizing, stop-loss, profit targets
- Analyzes: "Edge score 67/100, optimal position 3.5%, stop at -2.8%"
- Reasons: "Risk/reward favorable for 2-day hold, exit before earnings"
Team Leader (Final Synthesis with Reasoning):
- Thinks: "How do all these perspectives align?"
- Analyzes: "Finance shows opportunity but timing risk, Technical confirms entry, Sentiment is bullish, Risk is manageable"
- Reasons: "This is a valid 2-day trade with specific risk parameters"
- Synthesizes: "BUY $PATH for 2-day hold, 3.5% position, stop-loss at $X, exit before earnings on Day 3"
This isn't mechanical tool calling—it's intelligent reasoning at every step.
In trading, the difference between profit and loss often comes down to nuanced reasoning:
- Understanding why a stock is oversold (opportunity vs. falling knife)
- Recognizing when insider selling is a red flag vs. normal portfolio management
- Synthesizing conflicting signals (bullish technicals but bearish fundamentals)
- Timing entries and exits based on multiple risk factors
Agno's reasoning-first architecture makes this level of intelligence possible. The framework doesn't just execute tools—it enables agents to think, analyze, and reason like professional traders.
One of the most powerful demonstrations of Agno's flexibility is the ability to dynamically tune the Team Leader's "brain" based on user preferences. The system implements this through a risk profile selector that fundamentally changes how the Team Leader interprets agent data and formulates recommendations.
Different types of traders have vastly different risk tolerances and goals:
- Conservative Institutional Traders: Capital preservation is paramount. They seek 3-7% gains with tight stop-losses (-1.5% to -3%), avoiding binary events like earnings.
- Moderate Balanced Traders: Balanced approach seeking 5-10% gains with standard stop-losses (-3% to -5%), selective about high-risk catalysts.
- Aggressive Speculative Retail Traders: Maximum returns are the goal. They pursue 10-20%+ gains, comfortable with wide stop-losses (-5% to -8%), and embrace volatile catalyst-driven opportunities.
The same market analysis from agents needs to be translated differently for each profile. A "HIGH RISK" signal from the Risk Optimizer means something very different to a conservative vs. aggressive trader.
The system uses a slider selector in the Streamlit UI that lets users choose their trading profile. This selection doesn't just filter results—it dynamically prepends profile-specific instructions to the Team Leader before every analysis.
# User selects profile via color-coded slider
trading_profile_with_color = st.select_slider(
"Select Your Risk Profile:",
options=["🟢 Conservative", "🟡 Moderate", "🔴 Aggressive"],
value="🔴 Aggressive"
)
# Convert to clean profile name
trading_profile = profile_name_mapping[trading_profile_with_color]
# Result: "Aggressive"Visual Design:
- 🟢 Green = Safe, conservative approach
- 🟡 Yellow = Balanced, moderate risk
- 🔴 Red = Aggressive, high-risk/high-reward
When a profile is selected, the Team Leader receives contextual guidance on how to interpret agent data:
profile_instructions = {
"Aggressive": [
"🎯 **YOUR TRADER PROFILE: AGGRESSIVE SPECULATIVE RETAIL TRADER**",
"",
"**WHO YOU ARE:**",
"- High-risk tolerance retail trader seeking outsized returns",
"- Comfortable with volatility and binary events (earnings, catalysts)",
"- Embrace momentum, breakouts, and catalyst-driven opportunities",
"",
"**YOUR RECOMMENDATION APPROACH:**",
"- **Position Sizing:** AGGRESSIVE (multiply Risk Optimizer's output by 2-3x)",
"- **Stop-Loss Tolerance:** WIDE (-5% to -8%, wider than conservative -3%)",
"- **Entry Timing:** IMMEDIATE on strong signals",
"- **Catalyst Approach:** EMBRACE earnings and binary events",
"- **Confidence Threshold:** 50%+ is actionable",
"",
"**WHEN INTERPRETING RISK OPTIMIZER RESULTS:**",
"The Risk Optimizer returns CONSERVATIVE institutional-grade recommendations.",
"As an AGGRESSIVE trader, ADJUST these outputs:",
"",
"| Risk Optimizer Output | YOUR Aggressive Position Size |",
"| 2.0% (LOW risk) | 4-6% (double/triple) |",
"| 1.5% (MEDIUM risk) | 3-4.5% (double) |",
"| 1.0% (HIGH risk) | 2-3% (double) |",
"",
"**YOUR GOAL:** Identify and recommend the HIGHEST UPSIDE opportunities.",
]
}
# Get profile-specific instructions
trader_profile_intro = profile_instructions.get(trading_profile, "Aggressive")
# Prepend to Team Leader's base instructions
team = Team(
name="Trading Intelligence Team",
agents=[...],
instructions=trader_profile_intro + [ # Profile instructions FIRST
"🚀 ELITE MULTI-AGENT FINANCIAL INTELLIGENCE TEAM v2.0",
"Mission: Deliver institutional-grade SHORT-TERM TRADING OPPORTUNITIES",
# ... rest of base instructions ...
]
)Same Market Analysis, Different Interpretation:
Scenario: Risk Optimizer reports: "Edge score 65/100, recommended position 2%, stop-loss -3%"
Conservative Profile Output:
⚠️ MODERATE OPPORTUNITY - $APLD
- Position Size: 1.5% (reduced for safety)
- Stop-Loss: -2% (tighter than Risk Optimizer's -3%)
- Catalyst Risk: HIGH - Earnings in 2 days
- Recommendation: WAIT for post-earnings clarity
Aggressive Profile Output:
🚀 STRONG BUY OPPORTUNITY - $APLD
- Position Size: 4-6% (2-3x Risk Optimizer's output)
- Stop-Loss: -5% to -7% (wider for volatility room)
- Catalyst: Earnings in 2 days = MOMENTUM OPPORTUNITY
- Recommendation: BUY NOW - Ride earnings momentum
The exact same agent data (fundamentals, technicals, sentiment, risk metrics) is interpreted differently based on the user's selected profile.
This feature demonstrates several key advantages of agentic frameworks:
1. Dynamic Instruction Modification
Unlike static systems, Agno allows runtime modification of agent behavior through instruction prepending. The Team Leader's "personality" changes based on user context without touching agent code.
2. Intelligent Orchestration Without Hardcoding
The Team Leader doesn't have hardcoded logic like if profile == "Aggressive": multiply_position_by_2(). Instead, it reasons through the profile instructions using its LLM intelligence to apply them contextually to each unique stock situation.
3. Separation of Concerns
- Agents provide objective analysis (technicals, fundamentals, risk)
- Profile Instructions provide subjective interpretation guidance
- Team Leader synthesizes both into personalized recommendations
4. Adaptability Without Retraining
No model retraining, no rule changes in agent code. Just prepending different instructions creates fundamentally different trading behaviors—from ultra-conservative to highly aggressive.
This is what makes agentic systems fundamentally different from traditional algorithmic trading:
Traditional Algo Trading:
- Fixed rules: "If RSI < 30 and MACD bullish, BUY"
- Same logic for all users
- Requires code changes for different strategies
Agno-Based Agentic System:
- Flexible reasoning: "Interpret agent signals through risk profile lens"
- Adapts to each user's preferences dynamically
- Profile changes = instruction changes, no code deployment
The system becomes a "smart robot" that adapts its recommendations to the user's trading philosophy, not the other way around. The same intelligence infrastructure serves conservative pension fund managers and aggressive day traders—just with different contextual instructions.
This level of adaptability is achieved without touching agent code or retraining models—the Team Leader's behavior changes purely through instruction modification at runtime.
The architecture organizes six specialized agents into a coordinated trading intelligence system.
Before diving into the agent architecture, a critical question: how should these agents actually work together? Three orchestration patterns were evaluated before settling on coordinate mode.
1. Parallel Mode (delegate_task_to_all_members=True)
- Team Leader delegates to ALL agents simultaneously
- Fast, but no shared context between agents
- Problem: Technical Agent can't use Finance Agent's findings
- Use case: Independent tasks with no dependencies (e.g., summarizing multiple documents)
2. Sequential Broadcast Mode (respond_directly=True)
- Team Leader delegates to agents one after another in fixed order
- Each agent response goes directly to user (no synthesis)
- Critical limitation: Team Leader cannot make decisions between agents
- ❌ Cannot skip agents based on results
- ❌ Cannot change order based on conditions
- ❌ Cannot run conditional logic (if Finance finds 0 opportunities → skip Technical)
- Problem: Rigid workflow, no synthesis, just concatenated outputs
- Use case: Simple sequential task delegation with no conditional logic
Example of Sequential Broadcast:
Team(respond_directly=True) # Fixed sequence: Agent1 → Agent2 → Agent3 → Agent4
Query: "Find trading opportunities"
→ Finance Agent runs (finds 0 opportunities)
→ Technical Agent STILL runs (wastes time, no stocks to analyze)
→ Web Agent STILL runs (no stocks to research)
→ Sentiment Agent STILL runs (no stocks to check)
→ Result: 4 empty responses, no synthesis3. Coordinate Mode (Our Choice) - Intelligent Orchestration
Team(
delegate_task_to_all_members=False, # Team Leader decides WHO and WHEN
respond_directly=False, # Team Leader synthesizes
share_member_interactions=True # Agents share context
)The Critical Difference: Conditional Orchestration
In coordinate mode, the Team Leader is an intelligent orchestrator that makes decisions based on results:
# Team Leader Instructions (our actual implementation)
instructions = [
"Phase 1: Delegate to Finance Agent",
"IF Finance Agent finds 0 opportunities:",
" → SKIP all remaining phases",
" → Explain: 'No opportunities in current market conditions'",
" → STOP",
"",
"IF Finance Agent finds 1+ opportunities:",
" → Phase 2: MUST delegate to Technical Agent",
" → Phase 3: MUST delegate to Web + Sentiment (parallel)",
" → Phase 4: MUST delegate to Risk Optimizer",
" → Phase 5: Synthesize all findings",
"",
"IF Technical Agent flags high risk:",
" → Adjust Risk Optimizer parameters",
" → Request tighter stop-loss levels"
]Real Example: Conditional Orchestration in Action
Scenario A: No Opportunities Found
Query: "Find AI stocks under $50"
Phase 1: Finance Agent
→ Result: "No AI stocks under $50 meet our criteria"
Team Leader Decision:
✅ Skip Technical Agent (no stocks to validate)
✅ Skip Web Agent (no stocks to research)
✅ Skip Sentiment Agent (no stocks to check)
✅ Skip Risk Optimizer (no opportunities to size)
→ Final Response: "No trading opportunities found. Market conditions..."
Scenario B: Opportunities Found
Query: "Find AI stocks under $50"
Phase 1: Finance Agent
→ Result: "Found 3 opportunities: $PLTR, $AI, $SOUN"
Team Leader Decision:
✅ Delegate to Technical Agent (validate these 3)
✅ Delegate to Web + Sentiment (research these 3)
✅ Delegate to Risk Optimizer (size positions for these 3)
→ Final Response: "Top opportunity: $PLTR - BUY at $45.50..."
1. Efficiency Through Conditional Logic
❌ Sequential Broadcast: Always runs all 6 agents (60+ seconds)
✅ Coordinate Mode: Runs only necessary agents (15-60 seconds)
Example: "Are there important events tomorrow?"
→ Sequential Broadcast: Finance → Technical → Web → Sentiment → Risk (all run)
→ Coordinate Mode: Finance only (event detection), skips rest
2. Adaptive Workflow Based on Results
Finance finds 10 opportunities:
→ Team Leader: "Too many. Technical Agent: focus on top 3 by momentum"
Finance finds 0 opportunities:
→ Team Leader: "Stop workflow. No need for Technical/Sentiment analysis"
Technical flags extreme risk:
→ Team Leader: "Risk Optimizer: use conservative position sizing"
3. Complex Dependencies Requiring Intelligence
Phase 0 (Sector Mapper) → IF sector specified
↓
Phase 1 (Finance Agent) → ALWAYS run first
↓
Phase 1.5 (Technical Agent) → IF Finance found opportunities
↓
Phase 2 (Web Agent) → IF specific tickers identified
Phase 3 (Sentiment Agent) → IF specific tickers identified (parallel with Web)
↓
Phase 4 (Risk Optimizer) → IF opportunities + technical validation complete
↓
Phase 5 (Team Leader Synthesis) → ALWAYS (combines all findings)
4. Team Leader Can Synthesize Contradictions
# This requires Team Leader reasoning, impossible with respond_directly=True
Finance Agent: "BUY $AAPL - Strong fundamentals, insider buying"
Technical Agent: "NEUTRAL $AAPL - Overbought RSI, resistance at $195"
Sentiment Agent: "EXTREME BULLISH $AAPL - Reddit hype, potential exhaustion"
Team Leader Synthesis:
"Despite bullish fundamentals (Finance) and social sentiment (Sentiment),
technical indicators show overbought conditions with nearby resistance.
RECOMMENDATION: WAIT for pullback to $185 support before entry."The Decisive Advantage:
| Feature | Sequential Broadcast | Coordinate Mode |
|---|---|---|
| Agent Selection | All agents, fixed order | Selective, based on conditions |
| Conditional Logic | ❌ None | ✅ Full if/then orchestration |
| Early Exit | ❌ Always runs all agents | ✅ Skip remaining if Phase 1 fails |
| Adaptive Workflow | ❌ Rigid sequence | ✅ Adjust based on results |
| Synthesis | ❌ Concatenated outputs | ✅ Team Leader reasoning |
| Efficiency | ❌ Wastes time on empty results | ✅ Stops when appropriate |
Coordinate mode was chosen because trading requires intelligent decision-making at each phase, not just running a fixed sequence of agents. The Team Leader must decide which agents to call, when to stop, and how to synthesize conflicting signals—capabilities only coordinate mode provides.
Agno's coordinate mode provides automatic context sharing through a single primary mechanism:
When share_member_interactions=True, Agno automatically sends complete previous agent responses to subsequent agents:
Team(
share_member_interactions=True, # Enables automatic context sharing
...
)What Happens Under the Hood:
When Technical Agent runs after Finance Agent, Agno automatically prepends this to Technical Agent's context:
<member interactions>
Member: Finance Agent
Task: Analyze $AAPL for short-term trading opportunities
Response: **Trading Opportunities Found:**
- $AAPL: BUY signal at $185.50
- Entry: $185.50, Target: $192.00 (+3.5%)
- Catalyst: Earnings beat, insider buying detected
- Risk: High volatility (daily ATR $4.20)
</member interactions>
Now analyze technical entry/exit for the opportunities found above.
Technical Agent can now reference "the opportunities Finance Agent found" without any manual data passing.
Verified from Agno source code (team.py, _get_team_member_interactions_str() method):
# Agno's actual implementation
team_member_interactions_str = "<member interactions>\n"
for interaction in member_responses:
team_member_interactions_str += f"Member: {member_name}\n"
team_member_interactions_str += f"Task: {task}\n"
team_member_interactions_str += f"Response: {response_content}\n\n"
team_member_interactions_str += "</member interactions>\n"Agno also provides enable_agentic_state=True, which gives the Team Leader an update_session_state tool for explicit state management:
Team(
enable_agentic_state=True, # Optional: Team Leader gets update_session_state tool
...
)Why it's not used: share_member_interactions=True already provides all necessary context propagation. The Team Leader makes orchestration decisions by reading agent responses in the member interactions, not by explicitly storing/retrieving state.
If needed, it could be used like this:
# Team Leader could store structured data
update_session_state({
"mapped_sector": {"sector": "Technology", "etf": "XLK"},
"phase_1_complete": True
})Note: For member agents to access session_state, you would also need add_session_state_to_context=True. Our application relies entirely on share_member_interactions for context sharing.
Real Trading Impact:
By Phase 4, Risk Optimizer has cumulative context from all previous phases:
- ✅ Finance Agent's entry price ($185.50), fundamental catalysts
- ✅ Technical Agent's stop-loss ($182.00), profit targets
- ✅ Web Agent's catalyst research
- ✅ Sentiment Agent's conviction metrics (82% bullish)
Risk Optimizer calculates: Risk per share = $185.50 - $182.00 = $3.50, High conviction → 3% portfolio allocation → 85 shares position size.
Team Leader can synthesize contradictions:
- Finance says BUY (fundamentals strong)
- Technical confirms (trend valid)
- Sentiment shows exhaustion (overbought)
- Synthesis: "WAIT for pullback to $182 support"
The result: each agent contributes specialized expertise while building on complete collective intelligence from all previous phases, with zero manual context passing.
The system is built around coordinate mode orchestration—a pattern where specialized agents execute sequentially, each building on the previous agent's findings. Think of it as an assembly line for market intelligence, where each station adds a critical layer of analysis.
1. Sector Mapper Agent (Phase 0)
- Role: Market context and sector classification
- Tools: Sector mapping, market regime detection
- Output: Identifies which sector the stock belongs to and current market conditions
2. Finance Agent (Phase 1)
- Role: Comprehensive financial intelligence
- Tools: 98 financial analysis tools including:
- Real-time price feeds and earnings calendars
- Insider trading and institutional block trade detection
- Dark pool activity analysis (5 specialized tools)
- Congressional trading intelligence
- Regulatory intelligence (FDA approvals, clinical trials)
- Quick reversal signals and sentiment extremes
- Output: Identifies trading opportunities with risk factors and catalysts
3. Technical Analysis Agent (Phase 2)
- Role: Technical signals and strategy validation
- Tools: 22 technical tools including:
- Multi-timeframe analysis (1min to 1day)
- Support/resistance levels and momentum signals
- 13 ML-enhanced indicators (Random Forest, XGBoost, LightGBM)
- Walk-forward optimization for model validation
- Institutional-grade risk assessment
- Interactive Plotly visualizations
- Output: Entry/exit levels, stop-loss recommendations, strategy confidence scores
4. Web Research Agent (Phase 3)
- Role: Real-time market intelligence
- Tools:
- Rate-limited DuckDuckGo search
- FireCrawl for deep web research
- Exa semantic search
- Output: Breaking news, catalyst timing, market sentiment context
5. Sentiment Agent (Phase 3 - Parallel)
- Role: Social media and community sentiment
- Tools:
- Enhanced X (Twitter) sentiment analysis
- Trading Reddit sentiment (4 specialized tools)
- Contrarian signal detection
- Momentum and trend analysis
- Output: Social sentiment scores, momentum indicators, contrarian opportunities
6. Short-Term Risk Optimizer (Phase 4)
- Role: Risk-adjusted position sizing for 1-3 day trades
- Tools: 5 specialized optimization tools:
- Enhanced edge scoring (improves win rate from 51% to 57%)
- Optimal timeframe determination
- Position sizing optimization
- Stop-loss level calculation
- Profit target identification
- Output: Risk-adjusted recommendations with precise entry/exit timing
Powered by Claude Sonnet 4.5 (200K-1M token context window), the Team Leader:
- Delegates tasks to specialized agents based on dependencies
- Synthesizes findings across all phases
- Generates structured, actionable recommendations
- Saves complete analysis to markdown files for audit trails
Agno provides the foundation for this multi-agent trading system:
Key Features:
- Built-in reasoning capabilities (ReasoningTools)
- Multi-agent orchestration with coordinate mode
- Shared context management between agents
- Real-time streaming architecture
- Pre/post hooks for data validation
- Session persistence with PostgreSQL
- Model-agnostic (Claude, GPT-4, open-source LLMs)
How these features enable trading intelligence:
- Reasoning: Agents analyze patterns, not just execute tools
- Coordinate Mode: Sequential workflow with dependencies (Phase 0 → Phase 1 → ...)
- Shared Context: Each agent builds on previous findings
- Hooks: Fail-fast validation prevents decisions on bad data
- Streaming: Real-time visibility into 30-60 second analyses
According to Agno's documentation: "Tools are functions your Agno Agents can use to get things done."
Agno provides TWO options for tools:
| Option | Description | Example | When to Use |
|---|---|---|---|
| Built-in Toolkits | 120+ pre-built Toolkits from Agno | YFinanceTools, FirecrawlTools, ReasoningTools |
Use for common tasks (web search, APIs, file operations, reasoning) |
| Custom Toolkits | Build your own using Toolkit base class |
DarkPoolActivityTools, TechnicalAnalysisTools |
Use for domain-specific logic that doesn't exist in any framework |
Our Application Uses Both:
- 6 Agno built-in Toolkits: ReasoningTools, FileTools, YFinanceTools, FirecrawlTools, ExaTools, XTools
- 21+ Custom Toolkits: Built from scratch or extending Agno's built-in Toolkits
- Total: 27 Toolkits providing 125+ tools
The Hierarchy:
Agent
└── tools=[] # List of Toolkits or individual tools
└── Toolkit (e.g., TechnicalAnalysisTools)
├── Tool: calculate_rsi(symbol)
├── Tool: detect_support_levels(symbol)
└── Tool: analyze_bollinger_bands(symbol)
Key Terminology (from Agno docs):
- Tool = An individual callable function (e.g.,
calculate_rsi) - Toolkit = A class containing multiple related tools
- Agent = Has a
tools=[]parameter that accepts Toolkit instances or individual tool functions
Our Application - Combining Agno's Built-in + Custom Toolkits:
1. Agno's Built-in Toolkits (6 Toolkits):
ReasoningTools(think, analyze)FileTools(save_file for audit trails)YFinanceTools(base market data access)FirecrawlTools(web scraping)ExaTools(semantic web search)XTools(Twitter/X sentiment)
2. Our Custom Toolkits (21+ Toolkits):
- Built from scratch using
agno.tools.Toolkitbase class - Examples:
DarkPoolActivityTools,TechnicalAnalysisTools,ShortTermRiskOptimizationTools - Some extend Agno's built-in Toolkits (e.g.,
YFinanceToolsPatchedextendsYFinanceTools)
Total: 125+ tools from 27 Toolkits (6 built-in + 21+ custom)
In Streamlit UI: The interface displays individual tool executions, not Toolkits
Example - How Agno Registers Tools:
from agno.tools import Toolkit
class TechnicalAnalysisTools(Toolkit):
"""Each method becomes a callable tool."""
def calculate_rsi(self, symbol: str, period: int = 14) -> str:
"""Calculate Relative Strength Index for momentum analysis."""
# Agno automatically:
# 1. Registers this as a tool
# 2. Extracts parameter names and types
# 3. Makes it callable by the agent's LLM
return rsi_analysis
def detect_support_levels(self, symbol: str) -> str:
"""Identify key support/resistance levels."""
return support_resistance_levels
# Agent sees TWO tools from this Toolkit
agent = Agent(
tools=[TechnicalAnalysisTools()], # Toolkit instance
# Agent now has access to these tools:
# - calculate_rsi(symbol, period)
# - detect_support_levels(symbol)
)How Agents Call Tools - Two Approaches:
Approach 1: Explicit Tool References (The Approach Used)
Instructions explicitly mention tool names with parameters to ensure critical tools are executed:
# From Short-Term Risk Optimizer Agent instructions:
instructions = """
STEP 2: EXECUTE ALL 5 RISK OPTIMIZATION TOOLS (MANDATORY):
5. calculate_enhanced_edge_score(ticker, current_price, monthly_low, monthly_high, daily_volatility, market_cap)
6. determine_optimal_timeframe(ticker, has_catalyst, catalyst_days_away, momentum_strength, earnings_days_away)
7. optimize_position_sizing(ticker, edge_score, risk_level, timeframe_days, portfolio_value)
8. calculate_stop_loss_levels(ticker, entry_price, support_levels, daily_volatility)
9. identify_profit_targets(ticker, entry_price, resistance_levels, timeframe_days, daily_volatility)
"""Why Explicit Tool References:
- ✅ Guarantees execution of critical tools (e.g., all 5 risk optimization tools)
- ✅ Shows exact parameters needed (guides LLM on data requirements)
- ✅ Enforces workflow order (e.g., calculate edge score before position sizing)
- ✅ Documents tool names and signatures directly in instructions for clarity
From Team Leader instructions (Phase 4):
instructions = """
PHASE 4: Short-Term Risk Optimization
- Tool 1: calculate_enhanced_edge_score(ticker='TICKER', current_price=PRICE, monthly_low=LOW,
monthly_high=HIGH, daily_volatility=VOLATILITY_PCT, market_cap=MARKET_CAP, base_score=54.0)
- Example: calculate_enhanced_edge_score('SMCI', 22.50, 18.00, 45.00, 7.5, 500000000, 54)
- Purpose: Score opportunities with proven bonus criteria
- Tool 2: optimize_position_sizing(ticker='TICKER', edge_score=EDGE_SCORE,
risk_level='LOW/MEDIUM/HIGH', timeframe_days=DAYS, portfolio_value=100000.0)
- Example: optimize_position_sizing('SMCI', 79, 'MEDIUM', 2, 100000)
- Purpose: Professional position sizing (max 2% per trade)
"""Approach 2: General Task Descriptions (Agno Default)
Agno also supports general instructions where the LLM autonomously selects tools:
# Alternative approach (not our primary method):
instructions = """
Analyze the stock's technical indicators and identify entry points.
"""
# Agno provides all tool signatures to LLM
# LLM autonomously decides to call:
# - calculate_rsi(symbol='AAPL')
# - detect_support_levels(symbol='AAPL')
# - analyze_bollinger_bands(symbol='AAPL')Our Hybrid Strategy:
- Critical workflows: Explicit tool references (Risk Optimization, Data Validation)
- Exploratory analysis: General task descriptions (Finance Agent's Toolkits with 98 tools)
- Result: Guaranteed execution of mandatory tools + LLM flexibility for comprehensive analysis
The "Magic" Explained:
When you give an agent general instructions like "analyze technical indicators," how does the LLM know which tools to call? Here's Agno's internal mechanism:
Step 1: Function Registration (At Agent Initialization)
# Your Python function
def calculate_enhanced_edge_score(
ticker: str,
current_price: float,
monthly_low: float,
monthly_high: float,
daily_volatility: float,
market_cap: float
) -> str:
"""
Calculate enhanced edge score with proven bonus criteria.
Args:
ticker: Stock ticker symbol
current_price: Current stock price
monthly_low: Lowest price in last 30 days
monthly_high: Highest price in last 30 days
daily_volatility: Daily volatility percentage
market_cap: Market capitalization
Returns:
Enhanced edge score analysis with bonuses
"""
# Implementation
return edge_score_reportStep 2: Agno's Automatic Conversion (from function.py)
Agno's Function.from_callable() extracts:
# From lines 143-253 in agno/tools/function.py
from inspect import signature, getdoc
from typing import get_type_hints
from docstring_parser import parse
# 1. Extract function signature
sig = signature(calculate_enhanced_edge_score)
# Result: (ticker: str, current_price: float, monthly_low: float, ...)
# 2. Extract type hints
type_hints = get_type_hints(calculate_enhanced_edge_score)
# Result: {'ticker': str, 'current_price': float, ...}
# 3. Parse docstring
docstring = getdoc(calculate_enhanced_edge_score)
parsed_doc = parse(docstring)
# Result: description + parameter descriptions
# 4. Convert to JSON Schema (OpenAI function calling format)
function_spec = {
"name": "calculate_enhanced_edge_score",
"description": "Calculate enhanced edge score with proven bonus criteria.",
"parameters": {
"type": "object",
"properties": {
"ticker": {
"type": "string",
"description": "(str) Stock ticker symbol"
},
"current_price": {
"type": "number",
"description": "(float) Current stock price"
},
"monthly_low": {
"type": "number",
"description": "(float) Lowest price in last 30 days"
},
# ... all other parameters
},
"required": ["ticker", "current_price", "monthly_low", "monthly_high",
"daily_volatility", "market_cap"]
}
}Step 3: LLM Receives Tool Catalog
When you send a message to the agent, Agno automatically includes ALL tool specifications:
{
"model": "gpt-4o-mini",
"messages": [
{
"role": "system",
"content": "You are a short-term risk optimization agent..."
},
{
"role": "user",
"content": "Optimize SMCI for 1-3 day trading"
}
],
"tools": [
{
"type": "function",
"function": {
"name": "calculate_enhanced_edge_score",
"description": "Calculate enhanced edge score with proven bonus criteria.",
"parameters": { /* JSON Schema from Step 2 */ }
}
},
{
"type": "function",
"function": {
"name": "optimize_position_sizing",
"description": "Calculate optimal position size for 1-3 day trades.",
"parameters": { /* JSON Schema */ }
}
}
// ... ALL 125+ tools sent to LLM!
]
}Step 4: LLM Autonomous Decision (Approach 2)
The LLM reads:
- Your general instruction: "Optimize SMCI for 1-3 day trading"
- ALL available tool signatures (125+ tools)
- Each tool's name, description, and required parameters
The LLM thinks:
"To optimize for trading, need edge scores, position sizing, and risk levels. Available tools:
calculate_enhanced_edge_score- matches 'edge score' needoptimize_position_sizing- matches 'position sizing' needcalculate_stop_loss_levels- matches 'risk' need"
The LLM autonomously generates tool calls:
{
"tool_calls": [
{
"function": "calculate_enhanced_edge_score",
"arguments": {
"ticker": "SMCI",
"current_price": 22.50,
"monthly_low": 18.00,
"monthly_high": 45.00,
"daily_volatility": 7.5,
"market_cap": 500000000
}
}
]
}Step 5: Explicit Reference (Approach 1 - Our Method)
When instructions explicitly mention function names:
instructions = """
5. calculate_enhanced_edge_score(ticker, current_price, monthly_low, monthly_high, ...)
"""The LLM sees:
- The explicit function name in instructions:
calculate_enhanced_edge_score - The matching function in the tools catalog
- The exact parameters expected
The LLM thinks:
"Instructions explicitly specify calling
calculate_enhanced_edge_score. Tool is in catalog. Execute it."
This achieves ~100% execution reliability versus ~80-90% with general instructions.
Why Both Approaches Work:
| Mechanism | Approach 1 (Explicit) | Approach 2 (General) |
|---|---|---|
| Tool Catalog | ✅ LLM receives all 125+ tool specs | ✅ LLM receives all 125+ tool specs |
| Instruction Parsing | Sees tool name in instructions | Sees task description in instructions |
| Decision Process | "Instruction says call X → X in catalog → call X" | "Task needs X capability → tool Y provides X → call Y" |
| Execution Rate | ~100% (explicit = mandatory) | ~80-90% (LLM may miss or choose wrong tool) |
| Use Case | Critical workflows with mandatory tools | Exploratory analysis with flexible tool selection |
Agno's power comes from automatic function introspection:
- Your Python function → Agno extracts signature, types, docstring
- Converts to OpenAI function calling format (JSON Schema)
- Sends ALL available tools to LLM on every request
- LLM can call tools either:
- Explicitly (instructions specify which tools to call)
- Autonomously (it chooses based on task and tool descriptions)
No manual JSON schema writing required—Agno does it all automatically from your Python code.
Agno provides 120+ built-in Toolkits for common tasks (web search, file operations, APIs, databases, etc.). However, trading requires specialized domain intelligence that doesn't exist in any framework.
The Challenge: Agno's built-in Toolkits provide foundational capabilities (e.g., YFinanceTools for basic price data), but trading requires intelligent signal extraction beyond raw data. The system requires tools that can:
- Apply machine learning models to detect patterns
- Score opportunities with confidence metrics
- Adapt to changing market conditions
- Provide domain-specific trading intelligence
Solution: Build custom Toolkits using Agno's Toolkit base class, leveraging ML models within tools.
Design Decision: Instead of creating one massive "TradingToolkit" with 125 tools, 27 specialized Toolkits were architected, each focused on a specific domain.
Technical Advantages:
-
Agent Specialization - Each agent receives only relevant tools:
- Finance Agent: 98 tools (9 Toolkits) for fundamental analysis
- Technical Agent: 22 tools (6 Toolkits) for chart analysis
- Each agent's context window optimized for its domain
-
Maintainability - Isolated domains = easier debugging:
- Bug in insider trading analysis? Only affects
CongressionalTradingIntelligenceTools - Need to upgrade dark pool data? Only touch
DarkPoolActivityTools
- Bug in insider trading analysis? Only affects
-
Reusability - Toolkits can be shared across agents:
YFinanceToolsPatchedused by Finance, Technical, and Risk Optimizer- Each agent gets the same base data, different analytical tools
-
Context Window Efficiency - LLM receives only agent-specific tools:
- Finance Agent receives 98 tool schemas (~15K tokens)
- Not all 125 tools (~20K tokens)
- Saves 5K tokens per request for more analysis capacity
Two Ways to Build Custom Toolkits:
1. Extend Agno's Built-in Toolkit (YFinanceToolsPatched extends YFinanceTools):
from agno.tools.yfinance import YFinanceTools
class YFinanceToolsPatched(YFinanceTools):
"""Extends Agno's built-in YFinanceTools with custom enhancements."""
def __init__(self):
super().__init__() # Get all built-in YFinance tools
# Add our custom tools
self.register(self.analyze_insider_trades)
self.register(self.detect_institutional_blocks)
def analyze_insider_trades(self, symbol: str) -> str:
"""Custom tool: Analyze insider buying/selling patterns."""
# Our custom implementation
return insider_analysis
def detect_institutional_blocks(self, symbol: str) -> str:
"""Custom tool: Detect large institutional block trades."""
# Our custom implementation
return block_trade_analysis
# Agent gets: All YFinance built-in tools + our 2 custom tools2. Build From Scratch (100% Custom Toolkit with ML):
Example: MLSignalEnhancementTools (8 tools with ML)
from agno.tools import Toolkit
from sklearn.ensemble import RandomForestClassifier
class MLSignalEnhancementTools(Toolkit):
"""Custom Toolkit - ML-powered momentum and volatility prediction."""
def __init__(self):
super().__init__()
# Pre-trained models loaded at initialization
self.momentum_model = self._load_momentum_classifier() # Random Forest
self.volatility_predictor = self._load_volatility_model() # LSTM
def detect_ml_momentum_signals(self, symbol: str) -> str:
"""Use Random Forest to detect momentum shifts (85%+ accuracy)."""
# Engineer 40+ features: price, volume, sentiment
features = self._engineer_features(symbol)
# ML prediction: Probability + confidence
momentum_prob = self.momentum_model.predict_proba(features)[0][1]
confidence = max(self.momentum_model.predict_proba(features)[0])
top_drivers = self._get_feature_importance()
return f"""
ML Momentum Signal: {momentum_prob:.1%} probability (confidence: {confidence:.1%})
Top Drivers: {top_drivers}
"""
def predict_intraday_volatility(self, symbol: str) -> str:
"""Predict next-hour volatility using LSTM."""
tick_data = self._get_minute_bars(symbol, period='5d')
predicted_vol = self.volatility_predictor.predict(tick_data)
regime = self._classify_volatility_regime(predicted_vol)
return f"Predicted volatility: {predicted_vol:.2%} ({regime})"ML models are initialized once, then used by all tool functions for predictions.
Machine Learning Architecture: 3-Layer Pipeline
The system demonstrates Agno's capability to integrate sophisticated ML models through a layered architecture where each level builds on the previous:
Layer 1: Basic ML Enhancement (4 Models)
- RandomForestClassifier (100 estimators): Ensemble tree-based classification
- GradientBoostingClassifier (100 estimators): Sequential boosting for error correction
- SVM with RBF kernel: Non-linear pattern recognition with probability calibration
- MLPClassifier (Neural Network with 100-50 hidden layers): Deep learning for complex patterns
Purpose: Convert technical indicators (RSI, MACD, volume) into ML probabilities with ensemble voting.
Layer 2: Advanced Pattern Recognition
- XGBoost (200 estimators, learning rate 0.01): Gradient boosting for non-linear relationships
- LightGBM (200 estimators, 31 leaves): Fast gradient boosting with leaf-wise growth
- LSTM Neural Networks (TensorFlow/Keras): Time-series sequence prediction for price patterns
Purpose: Deep pattern recognition with walk-forward optimization to prevent overfitting.
Layer 3: Institutional Validation
- Ensemble Voting Classifier: Combines all models (soft voting with probability weighting)
- Walk-Forward Cross-Validation: Time-series split (5 folds) for robust validation
- Market Regime Detection: Adaptive model selection based on volatility/trend state
- Feature Importance Analysis: Recursive feature elimination to identify key drivers
Purpose: Robust validation ensuring no look-ahead bias or overfitting.
How Agno Enables This:
The critical advantage: Agno's automatic function introspection handles ML complexity automatically. The framework:
- Extracts function signatures from ML methods
- Converts complex types (numpy arrays, DataFrames) to JSON Schema
- Manages model state across tool calls within sessions
- Returns clean, actionable results to the LLM
The ML Advantage in Action:
| Traditional Approach | ML-Enhanced (3-Layer Pipeline) |
|---|---|
| RSI > 70 = "Overbought" | Layer 1: 78% momentum probability (4-model ensemble) Layer 2: LSTM predicts +$2.30 move Layer 3: 91% confidence (from model agreement) |
| Generic volatility lookback | LSTM predicts next-hour volatility: 2.3% (low regime) |
| Binary signals | Probabilistic scores with confidence intervals |
| No explainability | Feature importance: volume (0.32), sentiment (0.28), institutions (0.24) |
| Static thresholds | Adaptive to bull/bear/sideways market regimes |
Real-World Impact:
- Before ML: "RSI is 72, might be overbought"
- After ML (3 Layers): "Layer 1: 78% buy probability from 4-model ensemble. Layer 2: LSTM detects continuation pattern (+$2.30 target). Layer 3: 91% confidence from model agreement. Feature drivers: unusual volume (0.32), sentiment shift (0.28), institutional buying (0.24). Volatility: 1.8% (low) - favorable entry window."
Training Data:
- 100+ stocks across multiple sectors
- 5+ years of historical data per stock
- 25+ engineered features from technical indicators
- Real-time retraining as market regimes change
This demonstrates Agno's power: ML models that would typically require dedicated ML engineers and complex API design work seamlessly through simple Python functions with automatic introspection.
Claude Sonnet 4.5 (Team Leader)
- Extended context for synthesizing complex analyses
- Enhanced reasoning for multi-step decision-making
- Advanced tool use capabilities
- Extended autonomy for long-horizon tasks
GPT-4.1 (Specialized Agents)
- Cost-effective for focused tasks
- Fast response times for real-time analysis
- Reliable tool execution
- Consistent performance across agent types
In trading, fake data kills. The system implements multiple layers of validation:
Pre-Execution Validation (Pre-Hook):
def validate_critical_data_sources_before_analysis(run_input, team, **kwargs):
"""Validate all critical APIs before analysis begins"""
validation_results = {
'yfinance': check_yfinance_health(),
'bls_economic_data': check_bls_api_health(),
'sec_filings': check_sec_edgar_health(),
'twitter_api': check_twitter_api_health()
}
critical_failures = [k for k, v in validation_results.items() if not v['healthy']]
if critical_failures:
raise DataValidationError(
f"Critical data sources unavailable: {critical_failures}. "
"Analysis cannot proceed with incomplete data."
)Post-Execution Quality Report (Post-Hook):
def generate_comprehensive_data_quality_report(run_output, team, **kwargs):
"""Generate detailed data quality metrics after analysis"""
report = {
'tools_executed': len(run_output.tools or []),
'data_sources_accessed': extract_unique_data_sources(run_output.tools),
'validation_checks_passed': count_validation_checks(run_output.tools),
'fallback_data_used': detect_fallback_usage(run_output.tools),
'data_freshness': calculate_data_freshness(run_output.tools)
}
logger.info(f"📊 Data Quality Report: {report}")
return reportInline Validation: Every tool validates its output:
# Example: BLS Economic Data Validation
if latest_value is None or release_date is None:
st.error(f"⚠️ Incomplete data for {series_name}")
logger.warning(f"Skipping {series_name} - missing critical data")
continue # Skip this release, don't use fake dataThe application uses Streamlit for a professional, responsive interface:
Real-Time Streaming:
- Individual agent responses stream in dedicated expanders
- Team Leader synthesis streams in the main response area
- Tool executions display with icons, timing, and agent attribution
- No buffering—users see analysis as it happens
Tool Execution Visibility:
Stock Analysis Progress:
💰 Get Current Stock Price (Financial Data) - 0.1950s | 💰 Finance Agent
📈 Technical Indicators Analysis (Technical Analysis) - 0.3972s | 📈 Technical Agent
🌐 Rate-Limited DuckDuckGo News Search (Web Research) - 1.8571s | 🌐 Web Agent
📊 Enhanced XTools Search (Twitter Sentiment) - 35.1746s | 📊 Sentiment Agent
🛡️ Enhanced Edge Score Calculation (Risk Optimization) - 0.0989s | 🛡️ Risk Optimizer
Structured Output: The Team Leader delivers analysis in a consistent format:
- Executive Summary: 2-3 sentence overview with recommendation
- Phase-Specific Sections: Finance, Technical, Web, Sentiment, Risk
- Final Recommendation: Clear BUY/WAIT/AVOID with timing and 30-second summary
- Adaptive Structure: Only includes phases that were executed
Every query generates a markdown file for compliance and review:
Filename Format: {TICKER}_{YYYY-MM-DD}_{HH-MM-SS}_analysis.md
Content Includes:
- Complete synthesis with all recommendations
- Finance Agent findings (opportunities, earnings dates, risk factors)
- Technical Analysis results (strategy, entry/exit levels, confidence)
- Web Research intelligence (catalysts, news, market conditions)
- Sentiment Analysis (social media momentum)
- Risk Optimization (edge scores, position sizing, stop-loss, profit targets)
- Tool execution summary
Robust Filename Generation: The system handles any query type with multiple fallback layers:
# Extract ticker from question
ticker_match = re.search(r'\$?([A-Z]{1,5})\b', question)
# Fallback to query type classification
if ticker == "ANALYSIS":
if "find" in question or "best" in question:
ticker = "SCREENING"
elif "market" in question or "sector" in question:
ticker = "MARKET"
# ... more fallbacks
# Final fallback: timestamp-based naming
if not ticker or ticker.strip() == "":
ticker = f"QUERY_{datetime.now().strftime('%Y%m%d_%H%M%S')}"Core Financial Data:
- Real-time stock prices and company information
- Earnings dates and analyst recommendations
- Insider trading activity detection
- Institutional block trade analysis
Advanced Intelligence:
- Dark Pool Activity (5 tools): Volume patterns, smart money positioning, iceberg orders, cross-trading detection
- Congressional Trading Intelligence: Political alpha from STOCK Act filings
- Regulatory Intelligence: FDA approvals, clinical trial results, regulatory risks
- Quick Reversal Signals: Oversold bounces, volume surge reversals, sentiment extremes
Macro Intelligence:
- BLS economic indicators (CPI, PPI, Employment, GDP)
- Federal Reserve policy analysis
- Market regime detection
Traditional Indicators:
- Moving averages (SMA, EMA, WMA)
- Momentum indicators (RSI, MACD, Stochastic)
- Volatility measures (Bollinger Bands, ATR, Keltner Channels)
- Volume analysis (OBV, VWAP, Accumulation/Distribution)
ML-Enhanced Signals (3-Layer Pipeline):
- Layer 1 - Basic Enhancement (4 models): RandomForest, GradientBoosting, SVM, Neural Network (MLP)
- Layer 2 - Advanced Recognition (3 models): XGBoost, LightGBM, LSTM (TensorFlow/Keras)
- Layer 3 - Institutional Validation: Ensemble voting, walk-forward cross-validation, market regime detection
- Training: 100+ stocks, 5+ years data, 25+ engineered features, real-time retraining
- Output: Probabilistic signals with confidence scores and feature importance
Institutional-Grade Risk Assessment:
- Position sizing optimization
- Multi-position risk analysis
- Real-time signal validation
- Current market conditions assessment
- Comprehensive performance reports
Professional Visualizations:
- Interactive Plotly charts (technical analysis, strategy dashboard, indicator summaries)
- Real-time updates
- Multi-timeframe views
Web Research:
- Rate-limited DuckDuckGo for breaking news
- FireCrawl for deep fundamental research
- Exa for semantic search across financial content
Social Sentiment:
- Enhanced X (Twitter) Analysis: Real-time sentiment with retry logic
- Trading Reddit Intelligence (4 tools):
- Short-term trading sentiment
- Momentum and premium opportunities
- Contrarian signal generation
- Trend sentiment analysis
Enhanced Edge Scoring:
- Base score derived from real-time market analysis
- Bonuses for:
- Oversold conditions (+20 points)
- Optimal volatility (+15 points)
- Quality market cap (+10 points)
- Historical pattern match (+10 points)
- Result: Improves win rate from 51% to 57%
Position Sizing Optimization:
- Professional risk management (max 2% position, max -3% stop loss)
- Accounts for edge score, risk level, timeframe
- Adapts to portfolio value
Timeframe Determination:
- Momentum Scalping (1 day): 4-6% position, 1-2% stops, 8-20% targets
- Overnight Momentum (1-2 days): 3-4% position, 2-3% stops, 6-15% targets
- Catalyst Timing (2-3 days): 2-3% position, 3-4% stops, 5-12% targets
Stop-Loss & Profit Targets:
- Calculated from support/resistance levels
- Adjusted for daily volatility
- Considers timeframe and risk tolerance
The Streamlit interface provides real-time visibility into the multi-agent analysis. Here's how the key UI components are implemented:
Tools are displayed in real-time as they execute, with proper categorization and timing:
def display_tool_calls(tool_calls: List):
for tool in tool_calls:
category = self._categorize_tool(tool.tool_name)
execution_time = tool.metrics.duration if tool.metrics else None
status = "✅" if execution_time else "⏳"
timing = f"({execution_time:.2f}s)" if execution_time else "(running)"
st.markdown(f"{status} **{category}**: {tool.tool_name} {timing}")Key Features:
- Real-time updates: Tools appear as they execute, not at the end
- Smart categorization: 125+ tool executions grouped into 8 categories (Finance, Technical, Web, Sentiment, ML, Risk, Sector, Reasoning)
- Timing visibility: Execution time displayed for completed tools
- Agent attribution: Each tool shows which agent executed it
Agno yields different event types that must be handled separately:
def generate_ai_response(question: str):
resp_container = st.empty()
agent_content = {}
agent_containers = {}
for event in team.run(question, stream=True, stream_intermediate_steps=True):
if hasattr(event, 'tools'):
display_tool_calls(event.tools)
elif hasattr(event, 'agent_id'):
if event.agent_id not in agent_containers:
expander = st.expander(f"🤖 {get_agent_name(event.agent_id)}")
agent_containers[event.agent_id] = expander.empty()
agent_content[event.agent_id] = ""
agent_content[event.agent_id] += event.content
agent_containers[event.agent_id].markdown(agent_content[event.agent_id])
elif hasattr(event, 'team_id'):
resp_container.markdown(event.content)Key Implementation Decisions:
st.empty()Placeholders: Create once per agent, update in-place for smooth streaming (no flickering)- Event Type Detection: Check for
agent_idvsteam_idto route content correctly - Separate Accumulators: Each agent has its own content string to prevent mixing
- Expander Management: Agents get dedicated expanders, team leader uses main area
Session continuity enables context within the current conversation:
if "session_id" not in st.session_state:
st.session_state["session_id"] = str(uuid.uuid4())
team.run(question,
session_id=st.session_state["session_id"],
stream=True)Result: Within the current session, agents maintain conversation context and can reference previous queries and responses.
A permanent storage system prevents timing data loss during streaming:
if "timing_storage" not in st.session_state:
st.session_state.timing_storage = {}
tool_sig = f"{tool.tool_name}:{agent_id}"
if tool.metrics.duration:
st.session_state.timing_storage[tool_sig] = tool.metrics.duration
elif tool_sig in st.session_state.timing_storage:
tool.metrics.duration = st.session_state.timing_storage[tool_sig]Why This Matters: Agno can yield the same tool multiple times during streaming (initial execution, then completion). This system ensures completed tools (with timing) are never overwritten by running tools (without timing).
User Experience Benefits:
- Transparency: See exactly which tools are running in real-time
- Engagement: Progress visibility during 30-60 second analyses
- Trust: Tool execution timing builds confidence in data sources
- Debugging: Easy to identify which agent or tool encountered issues
Challenge: With 125+ tools across 27 Toolkits distributed among 6 agents, how do you correctly attribute each tool execution to the right agent in the UI?
Solution: Multi-layer detection with explicit tool-to-agent mapping:
# Explicit tool detection for specialized toolkits
if tool_name in ['calculate_enhanced_edge_score', 'optimize_position_sizing', ...]:
agent_id = "short-term-risk-optimizer"
category = "🛡️ Risk Optimization"
elif tool_name in ['get_current_stock_price', 'analyze_insider_trading_activity', ...]:
agent_id = "finance-agent"
category = "💰 Financial Data"
# ... 125+ tool mappingsEvery tool execution now shows the correct agent, icon, category, and timing.
Team Leader Instructions (Simplified):
instructions = [
"PHASE 0: SECTOR MAPPING (CONDITIONAL - only for screening queries)",
" └── Delegate to Sector Mapper Agent if user specified sector",
" └── Wait for completion before Phase 1",
"PHASE 1: FINANCIAL INTELLIGENCE",
" └── Delegate to Finance Agent",
" └── Share sector context if Phase 0 ran",
" └── Wait for completion before Phase 2",
"PHASE 2: TECHNICAL ANALYSIS (DEPENDS ON PHASE 1)",
" └── Delegate to Technical Agent",
" └── Share opportunities from Phase 1",
"PHASE 3: PARALLEL INTELLIGENCE (DEPENDS ON PHASE 1)",
" └── Delegate to Web Agent AND Sentiment Agent simultaneously",
"PHASE 4: RISK OPTIMIZATION (DEPENDS ON PHASES 1-3)",
" └── Delegate to Risk Optimizer",
" └── Share all previous findings",
"PHASE 5: SYNTHESIS (FINAL STEP)",
" └── Combine all findings",
" └── Generate structured recommendation",
" └── Save to file for audit trail"
]The result: clear dependencies, parallel execution where possible, guaranteed order of operations.
Each agent is a specialist with its own model, tools, and instructions. Here's how the intelligence is divided:
Role: Map user sector terms (like "biotech", "AI stocks") to valid YFinance sectors for screening queries
Key Tool:
map_sector_to_yfinance()- Intelligent sector mapping with AI reasoning
Why This Matters: When screening for opportunities (e.g., "Find 3 best tech stocks"), this agent translates user terms into YFinance-compatible sectors and generates industry keywords for precise filtering. Not needed for individual stock analysis.
Model: GPT-4.1 (fast, cost-effective for focused analysis)
Role: Comprehensive financial intelligence for opportunity identification
The Finance Agent is the most complex, with 9+ Toolkits providing 98 tools. Here's the agent structure:
The Hierarchy:
Finance Agent
└── tools=[...] # List of Toolkit instances
├── YFinanceToolsPatched (35+ tools)
├── DarkPoolActivityTools (5 tools)
├── ShortInterestDynamicsTools (4 tools)
├── CongressionalTradingIntelligenceTools (6 tools)
├── MarketWarningTools (12+ tools)
├── IntradayMomentumTools (8+ tools)
├── EnhancedCandlestickIntelligenceTools (6+ tools)
├── EventIntelligenceTools (9 tools - Event Detection & Impact Prediction)
└── InstitutionalMLTradingTools (12+ tools)
Total: 98 callable tools
Here's the code:
def create_finance_agent(db_url: str) -> Agent:
return Agent(
name="Finance Agent",
model=OpenAIChat(id="gpt-4.1"),
tools=[
YFinanceToolsPatched(),
DarkPoolActivityTools(),
ShortInterestDynamicsTools(),
CongressionalTradingIntelligenceTools(),
MarketWarningTools(enable_all=True),
IntradayMomentumTools(),
EnhancedCandlestickIntelligenceTools(),
EventIntelligenceTools(),
InstitutionalMLTradingTools(),
],
db=PostgresDb(db_url=db_url),
add_history_to_context=True,
num_history_runs=3,
instructions=["Focus on 1-3 day trading with real data"]
)Key Implementation Details:
- Tool Organization: 10 distinct phases, each with specialized toolkits
- Session Context: Maintains up to 3 previous interactions within the current session for conversational flow
- Real Data Only: Instructions emphasize no fallback or synthetic data
- Comprehensive Coverage: 98 tools execute for single-stock analysis
The Finance Agent answers a fundamental question: "Is there a financial reason to trade this stock in the next 1-3 days?" It detects:
- Insider buying before news breaks (Congressional Trading Intelligence)
- Institutional accumulation in dark pools (Dark Pool Activity Tools)
- Analyst upgrades driving momentum (Fundamental Analysis Tools)
- Earnings catalysts creating volatility opportunities (Event Intelligence Tools)
Critical Capability: Event Intelligence (Phase 9)
One of the Finance Agent's most powerful features is EventIntelligenceTools—a dedicated toolkit providing 1-5 day advance warning of market-moving events. This isn't just news aggregation; it's predictive intelligence.
The 9 Event Detection Tools:
EventIntelligenceTools(enable_all=True) # 9 specialized tools
├── detect_upcoming_events() # Scans 1-5 days ahead
├── predict_event_impact() # ML-based impact prediction
├── get_regulatory_intelligence() # Real-time FDA/SEC monitoring
├── analyze_historical_event_patterns() # Historical precedent analysis
├── generate_event_aware_strategy() # Strategy adjustments for event timing
├── monitor_real_time_developments() # Breaking event tracking
├── assess_event_market_positioning() # Pre-event market sentiment
├── generate_post_event_analysis() # Outcome validation
└── create_event_intelligence_summary() # Actionable synthesisWhat Makes This Critical for Short-Term Trading:
Traditional trading systems react to news after it breaks. This system predicts events before they're priced in, enabling strategic positioning:
- Fed Meeting in 3 Days: System detects macro volatility risk → Risk Optimizer reduces position sizes or delays entry
- Earnings Tomorrow: Finance Agent flags proximity → Technical Agent adjusts stop-loss wider → Risk Optimizer recommends exit before announcement
- FDA Decision This Week: Regulatory intelligence detects approval catalyst → System identifies biotech opportunity → Increased conviction for momentum play
- Jobs Report Friday: Economic calendar integration → System warns of Thursday positioning → Trading strategy adjusted to avoid pre-announcement volatility
Real-World Impact Example:
Without Event Intelligence:
- Tuesday: System recommends BUY at $50, 4% position, -3% stop-loss
- Wednesday (Surprise!): Earnings announced after-hours
- Thursday: Stock gaps down to $45 on earnings miss → -10% loss instead of -3%
With Event Intelligence:
- Tuesday:
detect_upcoming_events()finds earnings in 24 hours → Risk Optimizer flags proximity - Tuesday: System recommends: "WAIT for post-earnings clarity" or "Reduce position to 1.5%, widen stop to -5%, exit before close Wednesday"
- Wednesday: Earnings miss → No position = No loss, or minimal loss from reduced sizing
This timing advantage transforms how the system evaluates opportunities, ensuring risk management accounts for binary events.
Model: GPT-4.1 for cost-effective, reliable tool execution at scale
Role: Validate entry/exit timing and strategy confidence
The Technical Agent combines traditional technical analysis with ML-enhanced signals and institutional-grade risk assessment:
def create_technical_analysis_agent(db_url: str) -> Agent:
return Agent(
name="Technical Analysis Agent",
model=OpenAIChat(id="gpt-4.1"),
tools=[
TechnicalAnalysisTools(),
MultiTimeframeAnalysisTools(),
MLSignalEnhancementTools(),
AdvancedMLTradingTools(),
InstitutionalMLTradingTools(),
PlotlyVisualizationTools(),
],
db=PostgresDb(db_url=db_url),
add_history_to_context=True,
instructions=["Provide entry/exit timing with ML-enhanced signals"]
)Key Implementation Details:
- ML Integration: 60-day training windows optimized for short-term patterns (López de Prado methodology)
- Volume Confirmation: 15% signal boost for high volume, 15% reduction for low volume
- Multi-Timeframe: Daily, Hourly, 5-minute analysis with confluence detection
- Risk Assessment: Real-time position sizing with Sharpe ratio optimization
But finding an opportunity is only half the battle. Without proper entry/exit timing, even the best fundamental setup can fail. This agent answers:
- "Where to enter?" (support levels, breakout points with ML confirmation)
- "Where to exit?" (resistance levels, profit targets derived from technical analysis)
- "What's my risk?" (stop-loss levels calculated from ATR and support)
- "How confident is this strategy?" (ML confidence scores, real-time market validation)
Model: GPT-4.1 for fast, reliable technical analysis execution
Role: Real-time news, catalysts, and market intelligence
Key Tools (2+ specialized):
- News Intelligence: Rate-limited DuckDuckGo for breaking news
- Web Research: FireCrawl for deep fundamental research
Markets move on information, and timing matters. This agent detects:
- Breaking news before it's priced in
- FDA approvals, product launches, partnerships
- Competitive threats or advantages
- Macro events affecting the stock
Model: GPT-4.1 with web search tools (FireCrawl, DuckDuckGo)
Role: Social media momentum and retail sentiment
Key Tools (6+ specialized):
- Twitter/X Analysis: Real-time sentiment with retry logic
- Reddit Intelligence: Trading-focused sentiment from multiple subreddits
- Sentiment Scoring: Momentum and contrarian signal detection
Retail sentiment drives short-term momentum in ways institutional analysis often misses. This agent detects:
- Social media hype building before price moves
- Sentiment exhaustion (contrarian signals)
- Reddit/WSB coordination creating volatility
- Twitter influencer impact on price
Model: GPT-4.1 with social media APIs
Role: Position sizing, risk management, and edge scoring for 1-3 day trades
The Risk Optimizer is unique—it has custom-built tools specifically for short-term risk management:
def create_short_term_risk_optimizer_agent(db_url: str) -> Agent:
return Agent(
name="Short-Term Risk Optimizer",
model=OpenAIChat(id="gpt-4.1"),
tools=[ShortTermRiskOptimizationTools()],
db=PostgresDb(db_url=db_url),
add_history_to_context=True,
instructions=["Execute all 5 risk tools with real data from context"]
)Custom Risk Optimization Toolkit:
class ShortTermRiskOptimizationTools(Toolkit):
def __init__(self):
super().__init__(name="short_term_risk_optimization_tools")
self.register(self.calculate_enhanced_edge_score)
self.register(self.optimize_position_sizing)
self.register(self.determine_optimal_timeframe)
self.register(self.calculate_stop_loss_levels)
self.register(self.identify_profit_targets)
def calculate_enhanced_edge_score(self, ticker: str, current_price: float,
monthly_low: float, monthly_high: float,
daily_volatility: float, market_cap: float) -> str:
score = self._calculate_score(current_price, monthly_low, monthly_high,
daily_volatility, market_cap)
return f"**Edge Score: {score}/100**\n{self._format_breakdown()}"Key Implementation Details:
- Custom Tools: Built from scratch for short-term trading (not generic risk tools)
- Real Data Only: All calculations use data from shared context (previous agents)
- Markdown Output: Tools return formatted markdown for direct display
- Agno Registration:
self.register()ensures tools appear in execution logs
Great opportunity combined with bad risk management equals losses. This agent answers:
- "How much to risk?" (position sizing based on volatility and account size)
- "When to exit if wrong?" (stop-loss calculated from ATR and support)
- "When to take profits?" (profit targets based on resistance and risk/reward)
- "How good is this trade?" (edge score 0-100 with transparent breakdown)
Model: GPT-4.1 with 5 specialized risk optimization tools
Role: Orchestrate all agents and synthesize final recommendation
Tools: ReasoningTools + FileTools (for audit trail)
Why Claude Sonnet 4.5:
- Extended context window (200K-1M tokens) - can synthesize across all agent outputs
- Enhanced reasoning - understands contradictions and weighs conflicting signals
- Advanced tool use - coordinates 6 agents with complex dependencies
Instructions: 200+ lines of detailed workflow orchestration (Phase 0 → 1 → 2 → 3 → 4 → 5)
The Team Leader configuration is where everything comes together. Considerable time was spent refining these parameters—each one serves a specific purpose for building a reliable trading intelligence system.
def create_reasoning_finance_team(db_url: str) -> Team:
team_db = PostgresDb(
session_table="csp_reasoning_finance_team_sessions",
db_url=db_url
)
reports_dir = Path(__file__).parent / "trading_reports"
reports_dir.mkdir(exist_ok=True)
return Team(
name="Reasoning Finance Team",
id="csp_reasoning_finance_team",
model=Claude(id="claude-sonnet-4-5-20250929"),
tools=[
ReasoningTools(
enable_think=True,
enable_analyze=True,
add_instructions=True,
add_few_shot=True
),
FileTools(
base_dir=reports_dir,
enable_save_file=True,
enable_read_file=False
)
],
members=[sector_mapper, finance_agent, technical_agent,
web_agent, sentiment_agent, short_term_optimizer],
db=team_db,
delegate_task_to_all_members=False,
respond_directly=False,
share_member_interactions=True,
enable_agentic_state=True,
pre_hooks=[validate_critical_data_sources_before_analysis],
post_hooks=[generate_comprehensive_data_quality_report],
tool_hooks=[logger_hook],
debug_mode=True,
show_members_responses=True,
instructions=[...] # 200+ lines of workflow orchestration
)Claude Sonnet 4.5 for Team Leader:
- Extended context window (200K-1M tokens) to synthesize across all 6 agents
- Enhanced reasoning for handling contradictions (bullish fundamentals vs bearish technicals)
- Advanced tool use for coordinating complex multi-phase workflows
ReasoningTools Configuration:
ReasoningTools(
enable_think=True, # MANDATORY: Team Leader must think before delegating
enable_analyze=True, # Evaluates member agent outputs before synthesis
add_instructions=True, # Adds Agno's DEFAULT_INSTRUCTIONS ("You must ALWAYS think before...")
add_few_shot=True # Includes examples of think→analyze→final_answer workflow
)Why This Matters for Team Leader:
The Team Leader uses ReasoningTools for intelligent orchestration decisions:
User asks: "Find AI stocks under $50"
Team Leader's Internal Reasoning (not shown to user):
1. think(
title="Plan workflow",
thought="User wants AI stocks under $50. Need to: (1) delegate to Finance Agent for screening, (2) evaluate if results warrant Technical analysis, (3) decide if Web/Sentiment needed",
action="Delegate to Finance Agent first",
confidence=0.9
)
2. [Delegates to Finance Agent → receives: "Found 3 opportunities: $PLTR, $AI, $SOUN"]
3. analyze(
title="Evaluate Finance results",
result="Finance found 3 valid opportunities with bullish catalysts",
analysis="3 opportunities justify full pipeline. Must validate technical entry levels and sentiment momentum.",
next_action="continue",
confidence=0.95
)
4. think(
title="Plan Technical delegation",
thought="Need precise entry/exit for these 3 tickers. Technical Agent should validate support/resistance.",
action="Delegate to Technical Agent with specific tickers from Finance",
confidence=0.9
)
5. [Continues through all phases with think→delegate→analyze cycles]
6. analyze(
title="Final synthesis",
result="Finance: bullish, Technical: confirmed entries, Sentiment: strong momentum",
analysis="All agents agree. $PLTR shows best setup: entry $9.20, target $10.50, strong Reddit sentiment.",
next_action="final_answer",
confidence=0.92
)
Team Leader's Final Response to User:
"Top opportunity: $PLTR at $9.20 (BUY). Target: $10.50 (+14.1%). Strong fundamentals + technical breakout + high social sentiment. Risk: Stop at $8.80 (-4.3%)."
Without ReasoningTools, the Team Leader would mechanically delegate to all agents even if Phase 1 found zero opportunities, wasting 40+ seconds on unnecessary analysis.
With ReasoningTools, the Team Leader thinks critically at each phase decision point, ensuring efficient, intelligent orchestration.
FileTools for Audit Trail:
- Every analysis saved to markdown files with timestamps
- Read-only disabled for security (write-only audit logs)
- Enables compliance review and pattern analysis
Session-Only Storage (No Cross-Session Memory):
db=PostgresDb(
session_table="csp_reasoning_finance_team_sessions",
db_url=db_url
)
# Note: add_history_to_context=False (default)
# Note: enable_agentic_memory=False (default)Why This Matters for Trading:
This is a deliberate architectural decision. The system does NOT store memories across sessions because:
- Market Conditions Change: Yesterday's analysis shouldn't bias today's market assessment
- Contamination-Free Analysis: Each trading decision must be based on current data only
- Objective Evaluation: No anchoring bias from previous recommendations
- Regulatory Compliance: Clean audit trail without historical contamination
What IS Stored (Current Session Only):
- Conversation messages within the active session
- Tool execution logs for the current analysis
- Session state during runtime (cleared after completion)
What is NOT Stored (Cross-Session):
- Historical analyses from previous sessions
- User preferences or trading patterns
- Agent "learning" from past recommendations
This means every query starts fresh, analyzing current market conditions objectively without bias from historical analyses.
Coordinate Mode Configuration:
delegate_task_to_all_members=False # Sequential execution
respond_directly=False # Team leader synthesizes
share_member_interactions=True # Agents see previous outputs
enable_agentic_state=True # Shared context toolsHow This Enables Sequential Workflow:
delegate_task_to_all_members=False: Team Leader controls agent order (Phase 0 → 1 → 2 → 3 → 4)respond_directly=False: Team Leader synthesizes all outputs (not just concatenation)share_member_interactions=True: Each agent receives full conversation history from previous agentsenable_agentic_state=True: Enablesset_shared_context()/get_shared_context()tools for runtime state
Example Flow:
# Phase 1: Finance Agent stores findings
set_shared_context('trading_opportunities', opportunities)
# Phase 2: Technical Agent reads Phase 1 data
opportunities = get_shared_context('trading_opportunities')
# Validates each opportunity with technical analysis
# Phase 4: Risk Optimizer uses ALL previous data
opportunities = get_shared_context('trading_opportunities')
technical_levels = get_shared_context('technical_analysis')
sentiment_scores = get_shared_context('opportunity_sentiment')
# Calculates position sizing, stop-loss, profit targetsThree-Layer Validation System:
pre_hooks=[validate_critical_data_sources_before_analysis]
post_hooks=[generate_comprehensive_data_quality_report]
tool_hooks=[logger_hook]Pre-Hook (Fail-Fast Validation):
- Tests YFinance, BLS, SEC APIs before analysis starts
- Prevents decisions on stale/missing data
- Raises
DataValidationErrorif critical sources unavailable
Post-Hook (Quality Metrics):
- Tools executed count
- Data sources accessed
- Validation checks passed
- Fallback data detection
- Data freshness timestamps
Tool Hook (Execution Logging):
- Logs every tool call with parameters
- Tracks execution timing
- Enables debugging and performance optimization
debug_mode=True
show_members_responses=TrueWhy Enable Debug Mode:
- Transparency: Users see exactly which agent and tool produced each insight
- Troubleshooting: Easy to identify API failures or data gaps
- Confidence Building: Detailed logging builds trust in recommendations
- Audit Trail: Complete execution trace for compliance review
All Members Use:
- Model: GPT-4.1 (cost-effective, fast, reliable)
- Database: Individual session tables per agent (isolation)
- Session Persistence: Conversation history within current session only
- No Cross-Session Memory: Each analysis is independent
Why GPT-4.1 for Agents vs Claude for Leader:
- Cost Efficiency: 6 agents × 20-30 tool calls = hundreds of API requests per query
- Speed: GPT-4.1 faster response times for tool execution
- Reliability: Consistent performance across specialized tasks
- Context: Agents work with focused data (single domain), don't need extended context
Team Leader Needs Claude Because:
- Must synthesize across all 6 agents (large context)
- Must reason through contradictions (enhanced reasoning)
- Must orchestrate complex dependencies (advanced tool use)
What was NOT included is as revealing as what was included:
❌ Cross-Session Memory:
# NOT USED (defaults):
enable_agentic_memory=False
enable_user_memories=False
add_history_to_context=FalseEach trading session must be independent. Historical bias could contaminate current market analysis.
❌ Knowledge Base:
# NOT USED (defaults):
knowledge=None
search_knowledge=True # Irrelevant without knowledge baseData comes from live APIs (YFinance, BLS), not a static knowledge base. Markets change too fast for pre-indexed data.
❌ Session Summaries:
# NOT USED (defaults):
enable_session_summaries=False
add_session_summary_to_context=NoneNot needed for single-session analysis. Each query completes in 30-60 seconds with full detail.
| Component | Value | Purpose |
|---|---|---|
| Team Leader Model | Claude Sonnet 4.5 | Extended context, enhanced reasoning |
| Agent Models | GPT-4.1 | Cost-effective, fast, reliable |
| Database | PostgresDb (session-only) | Current session history only |
| Orchestration | Coordinate Mode | Sequential phases with dependencies |
| Context Sharing | Enabled | Agents build on previous findings |
| Agentic State | Enabled | Runtime state tools (set_shared_context) |
| Cross-Session Memory | Disabled | Each session is independent |
| Hooks | Pre + Post + Tool | Data validation + quality + logging |
| Tools | Reasoning + File | Intelligence + audit trail |
| Debug Mode | Enabled | Transparency and troubleshooting |
This configuration delivers contamination-free, objective trading analysis where each session provides fresh insights based solely on current market conditions—ensuring unbiased analysis for every query
Building this system wasn't straightforward. Early prototypes worked in demos but failed in real use. Tools would execute but attribution was wrong. Streaming would buffer unexpectedly. Data quality issues would surface only after analysis completed.
Here are the three hardest technical challenges encountered and their solutions:
Problem: With 6 agents sharing some Toolkits (e.g., ReasoningTools provides think() and analyze() to all agents) and each having 15-30 specialized tools from domain-specific Toolkits, how do you correctly attribute which agent executed which tool in the UI?
Solution: Built a sophisticated tool attribution system that:
- Tracks
agent_idfromToolExecutionevents - Maps tool names to agent-specific categories (Finance, Technical, Web, etc.)
- Handles shared tools (ReasoningTools) by checking execution context
- Displays tools in real-time with proper icons and timing
Implementation:
def display_tool_calls(event: TeamRunOutputEvent):
tool_call = event.content
# Extract agent_id from tool execution
agent_id = None
if isinstance(tool_call, dict):
agent_id = tool_call.get("agent_id")
elif hasattr(tool_call, "agent_id"):
agent_id = getattr(tool_call, "agent_id")
# Map tool name to agent category
tool_name = tool_call.get("name") if isinstance(tool_call, dict) else getattr(tool_call, "name")
# Agent-specific tool detection
if "dark_pool" in tool_name or "insider" in tool_name:
agent_category = "Finance"
elif "rsi" in tool_name or "support_resistance" in tool_name:
agent_category = "Technical"
elif "calculate_enhanced_edge_score" in tool_name:
agent_category = "Risk Optimizer"
elif agent_id:
agent_category = agent_id.replace("-", " ").title()
# Display in UI with proper attribution
st.markdown(f"**{agent_category}:** {display_name}")This solved the trust problem—users can now see which agent is responsible for each insight, critical for debugging and building confidence in the system.
Problem: Agno's built-in async streaming (team.arun()) yields different event types (RunContent from agents, TeamRunContent from team leader, ToolExecution for tools). How do you stream everything in real-time without buffering or duplicate content?
Solution: Leveraged Agno's native streaming events with event-type differentiation and st.empty() placeholders:
- Individual agent content → separate expanders with in-place updates
- Team leader synthesis → main response area
- Tool executions → dedicated tool display with timing
- Content deduplication to prevent Agno's accumulated chunks from showing multiple times
Implementation:
async for event in team.arun(...):
if event.event == TeamRunEvent.run_content:
# Individual agent content
if isinstance(event.content, RunContent):
agent_id = event.content.agent_id
content = event.content.content
# Create agent-specific expander if not exists
if agent_id not in agent_containers:
agent_containers[agent_id] = st.expander(agent_id).empty()
agent_content[agent_id] = ""
# Accumulate and display
agent_content[agent_id] += content
agent_containers[agent_id].markdown(agent_content[agent_id])
elif event.event == TeamRunEvent.team_run_content:
# Team leader synthesis
content = event.content.content
team_leader_content += content
resp_container.markdown(team_leader_content)
elif event.event == TeamRunEvent.tool_call_completed:
# Tool executions
display_tool_calls(event)The result: zero buffering. Users see analysis happening live, even for 60-second queries. This transformed the UX from "waiting anxiously" to "watching intelligence unfold."
Problem: Trading decisions based on stale or missing data can lose money. How do you guarantee data quality without slowing down analysis?
Solution: Implemented Agno's pre/post hook system:
- Pre-hook: Validates all critical APIs (YFinance, BLS, FRED) before analysis starts. Fails fast if data unavailable.
- Post-hook: Generates data quality report (tools executed, data sources accessed, timestamps)
- Inline validation: Each tool checks for
Nonevalues and data freshness
Implementation:
def validate_critical_data_sources_before_analysis(team: Team, run_response: TeamRunResponse):
"""Pre-hook: Validate all critical APIs before analysis starts."""
critical_apis = {
"YFinance": lambda: yf.Ticker("AAPL").info is not None,
"BLS": lambda: requests.get("https://api.bls.gov/publicAPI/v2/timeseries/data/").status_code == 200,
"FRED": lambda: requests.get("https://fred.stlouisfed.org/").status_code == 200
}
failed_apis = []
for api_name, validator in critical_apis.items():
try:
if not validator():
failed_apis.append(api_name)
except Exception:
failed_apis.append(api_name)
if failed_apis:
raise RuntimeError(f"Critical APIs unavailable: {', '.join(failed_apis)}")
# Register pre-hook with Team
team = Team(
pre_hooks=[validate_critical_data_sources_before_analysis],
post_hooks=[generate_comprehensive_data_quality_report],
...
)Pre-hook validation now ensures no analysis proceeds with incomplete data, maintaining data integrity for trading decisions.
Agno Framework Advantages Demonstrated:
-
Reasoning-First Architecture: ReasoningTools enforces a
think()→ [tool calls] →analyze()→ final_answer workflow. Agents MUST reason before acting (Agno enforces: "You must ALWAYS think before making tool calls"). This transforms agents from mechanical signal generators into intelligent analysts that validate assumptions, cross-check data, and synthesize contradictions. The reasoning chain is cumulative—each thought builds on previous steps stored in session_state. -
Coordinate Mode for Dependencies: Sequential execution with
delegate_task_to_all_members=Falseensures Phase 1 completes before Phase 2, enabling proper context flow and dependency management. -
Shared Context Management:
share_member_interactions=Trueallows each agent to access previous agent outputs, enabling coherent multi-phase analysis without manual context passing. -
Data Validation Hooks: Pre-hooks for data validation and post-hooks for quality reporting provide fail-fast behavior and comprehensive observability.
-
Real-Time Streaming: Agno's event system (
RunContent,TeamRunContent,ToolExecution) enables granular streaming control for responsive UX. -
Session-Only Persistence:
add_history_to_context=Truemaintains conversation context within the current session only. Cross-session memory is deliberately disabled to ensure objective, contamination-free trading analysis.
This multi-agent system for identifying short-term trading opportunities demonstrates the Agno framework's capabilities for building intelligent analysis applications:
Framework Advantages Utilized:
-
Reasoning-First Architecture: ReasoningTools enable agents to think, analyze, and synthesize rather than mechanically execute tools
-
Coordinate Mode Orchestration: Sequential execution with dependencies ensures proper workflow management across 6 specialized agents
-
Shared Context Management: Built-in context sharing eliminates manual state management between agents
-
Framework Features: Pre/post hooks, session persistence, real-time streaming, and audit trails are framework-native
-
Extensible Design: Adding new agents or tools requires minimal changes to existing architecture
Technical Architecture:
- 6 specialized agents, each with domain-specific Toolkits:
- Finance Agent (98 tools from 9+ Toolkits)
- Technical Analysis Agent (22 tools from 6+ Toolkits)
- Web Research Agent (2+ tools from 3 Toolkits)
- Sentiment Agent (6+ tools from 4 Toolkits)
- Risk Optimizer Agent (5 tools from 1 custom Toolkit)
- Sector Mapper Agent (3 tools from 1 Toolkit)
- 125+ total tools organized into toolkits with proper registration and attribution
- Coordinate mode for sequential phase execution with dependencies
- Claude Sonnet 4.5 for team leader synthesis (extended context, enhanced reasoning)
- GPT-4.1 for specialized agents (cost-effective, reliable tool execution)
- PostgreSQL for session persistence (no cross-session memory)
- Streamlit with real-time streaming for responsive UX
The system architecture is extensible, the code follows Agno patterns, and the implementation demonstrates solid engineering practices for multi-agent systems.
Framework: Agno (v2.1.1) Models: Claude Sonnet 4.5 (Team Leader), GPT-4.1 (6 Specialized Agents) Agents: 6 specialized (Sector Mapper, Finance, Technical, Web, Sentiment, Risk Optimizer) Tools: 125+ callable tools from 27 Toolkits:
Custom Toolkits (21+ Toolkits, 119+ tools):
- Finance: 98 tools from custom Toolkits (DarkPoolActivityTools, CongressionalTradingIntelligenceTools, etc.)
- Technical: 22 tools from TechnicalAnalysisTools Toolkit
- Risk: 5 tools from ShortTermRiskOptimizationTools Toolkit
- Sector: 3 tools from SectorMappingTools Toolkit
- Plus 10+ other custom Toolkits (ML, Sentiment, etc.)
Agno's Built-in Toolkits (6 Toolkits, 6+ tools):
- ReasoningTools (think, analyze)
- FileTools (save_file)
- YFinanceTools (extended by our YFinanceToolsPatched)
- FirecrawlTools (web scraping)
- ExaTools (semantic search)
- XTools (Twitter/X sentiment)
Infrastructure:
- Database: PostgreSQL with PgVector (Agno-native session persistence)
- UI: Streamlit with real-time streaming (via Agno's
team.arun()async events)
Key Application Features:
- Dynamic Trading Profiles: 3 risk levels (Conservative 🟢 / Moderate 🟡 / Aggressive 🔴) with profile-specific Team Leader instructions
- Event Intelligence: 9 event types with 1-5 day advance detection (Fed, Earnings, FDA, SEC, Political, Economic, Corporate, Geopolitical, Options)
- File Output: Automatic audit trail generation (saves full analysis to timestamped
.mdfiles) - Real-Time Streaming: Live tool execution visibility and progressive response generation
Agno Features Utilized:
- ReasoningTools (think, analyze)
- Team coordinate mode
- Shared context management
- Pre/post hooks
- Session persistence (within-session only, no cross-session memory)
- Real-time streaming events
- Tool registration and attribution
This application would not have been possible without the Agno framework. Full credit goes to Ashpreet Bedi and the Agno team for building a framework that prioritizes simplicity over complexity, achieving industry-leading performance, creating robust infrastructure, and demonstrating that sophisticated multi-agent systems don't require convoluted abstractions—just clear thinking and pure Python.
Most importantly, building agentic systems with Agno is genuinely fun and satisfying—watching intelligent agents collaborate to solve complex problems never gets old.
This article presents a technical architecture for building multi-agent systems using the Agno framework to identify trading opportunities through intelligent analysis. The implementation demonstrates Agno's capabilities for multi-agent orchestration, reasoning, and data validation. Readers are encouraged to adapt these patterns to their specific use cases and requirements.