TradingAgents/CLAUDE.md

17 KiB

Project

TradingAgents — Options Trading Module

An options trading analysis module for TradingAgents — a multi-agent AI system that uses LLM-powered agent teams to analyze financial markets. The new module adds a parallel options analysis team that evaluates options chains, Greeks, volatility surfaces, dealer positioning, and options flow to recommend specific multi-leg options strategies with transparent reasoning.

Core Value: Agents produce actionable multi-leg options recommendations (with specific contracts AND alternative ranges) backed by transparent, educational reasoning that helps the user both trade and learn.

Constraints

  • Data providers: Tradier (REST, 120 req/min, Greeks hourly) and Tastyworks (REST + WebSocket streaming) as primary options data sources
  • No 2nd-order Greeks from API: Charm, Vanna, Volga must be calculated from 1st-order Greeks + Black-Scholes
  • Architecture: Must follow existing patterns — agent factory functions, vendor routing, LangGraph StateGraph
  • Python: >=3.10, consistent with existing codebase
  • LLM provider agnostic: Options agents must work with any supported LLM provider via the client factory

Technology Stack

Languages

  • Python >=3.10 - Entire codebase (agents, dataflows, CLI, graph orchestration)
  • None detected

Runtime

  • Python 3.10+ (compatible up to 3.13 per uv.lock resolution markers)
  • uv (primary - uv.lock present at project root)
  • pip/setuptools (build backend, pyproject.toml uses setuptools>=61.0)
  • Lockfile: uv.lock present

Frameworks

  • LangGraph >=0.4.8 - Multi-agent workflow orchestration via StateGraph (tradingagents/graph/setup.py)
  • LangChain Core >=0.3.81 - Base abstractions for LLM agents, callbacks, messages
  • langchain-openai >=0.3.23 - OpenAI, Ollama, OpenRouter, xAI via ChatOpenAI (tradingagents/llm_clients/openai_client.py)
  • langchain-anthropic >=0.3.15 - Anthropic Claude via ChatAnthropic (tradingagents/llm_clients/anthropic_client.py)
  • langchain-google-genai >=2.1.5 - Google Gemini via ChatGoogleGenerativeAI (tradingagents/llm_clients/google_client.py)
  • langchain-experimental >=0.3.4 - Experimental LangChain features
  • Typer >=0.21.0 - CLI framework (cli/main.py)
  • Rich >=14.0.0 - Terminal UI, panels, spinners, tables (cli/main.py)
  • Questionary >=2.1.0 - Interactive prompts
  • No test framework declared in pyproject.toml. One test file exists: tests/test_ticker_symbol_handling.py
  • setuptools >=80.9.0 - Build backend
  • uv - Package/dependency management

Key Dependencies

  • langgraph >=0.4.8 - Core orchestration engine; all agent workflows are LangGraph StateGraph instances compiled and executed via .stream() / .invoke()
  • langchain-core >=0.3.81 - Provides BaseCallbackHandler, message types (AIMessage), and tool abstractions used throughout
  • yfinance >=0.2.63 - Default financial data vendor for stock prices, fundamentals, news, insider transactions
  • backtrader >=1.9.78.123 - Backtesting engine (imported but usage not prominent in core flow)
  • pandas >=2.3.0 - DataFrame operations for financial data manipulation (tradingagents/dataflows/)
  • stockstats >=0.6.5 - Technical indicator calculations on stock data (tradingagents/dataflows/stockstats_utils.py)
  • rank-bm25 >=0.2.2 - BM25 lexical similarity for agent memory retrieval (tradingagents/agents/utils/memory.py)
  • parsel >=1.10.0 - HTML/XML parsing (likely for web scraping)
  • requests >=2.32.4 - HTTP client for Alpha Vantage API calls (tradingagents/dataflows/alpha_vantage_common.py)
  • redis >=6.2.0 - Redis client (declared as dependency, usage not prominent in core flow)
  • python-dotenv - Environment variable loading from .env files (main.py, cli/main.py)
  • tqdm >=4.67.1 - Progress bars
  • pytz >=2025.2 - Timezone handling

Configuration

  • .env file present - loaded via python-dotenv at startup
  • .env.example documents required API keys: OPENAI_API_KEY, GOOGLE_API_KEY, ANTHROPIC_API_KEY, XAI_API_KEY, OPENROUTER_API_KEY
  • ALPHA_VANTAGE_API_KEY - Required when using Alpha Vantage data vendor
  • TRADINGAGENTS_RESULTS_DIR - Optional, defaults to ./results
  • tradingagents/default_config.py - Central config dict (DEFAULT_CONFIG) controlling:
  • pyproject.toml - Project metadata, dependencies, entry points, package discovery

Data Storage

  • tradingagents/dataflows/data_cache/ - Cached financial data
  • eval_results/{ticker}/ - Logged trading states as JSON
  • results/ - Trade results output directory
  • redis >=6.2.0 declared as dependency. Connection details would come via environment config.

CLI Entry Point

  • Maps to cli.main:app (Typer application)
  • Fetches announcements from https://api.tauric.ai/v1/announcements (cli/config.py)

Platform Requirements

  • Python 3.10+
  • uv package manager (recommended) or pip
  • At least one LLM provider API key (OpenAI, Anthropic, Google, xAI, or OpenRouter)
  • Redis server (if redis-based features are used)
  • Same as development; runs as a Python CLI application
  • No containerization or deployment configs detected

Conventions

Naming Patterns

  • Use snake_case.py for all Python modules: bull_researcher.py, agent_states.py, y_finance.py
  • No hyphens in file names; underscores only
  • Module names describe the single responsibility: signal_processing.py, conditional_logic.py
  • Use snake_case for all functions: create_bull_researcher(), get_stock_data(), process_signal()
  • Factory functions use create_ prefix: create_fundamentals_analyst(), create_llm_client(), create_trader()
  • Getter functions use get_ prefix: get_config(), get_memories(), get_vendor()
  • Private/internal methods use _ prefix: _get_provider_kwargs(), _log_state(), _rebuild_index()
  • Use snake_case for all variables: curr_situation, past_memory_str, trade_date
  • Abbreviations are common and accepted: llm, curr_date, curr_date_dt
  • Config keys use snake_case strings: "deep_think_llm", "max_debate_rounds", "data_vendors"
  • Use PascalCase: TradingAgentsGraph, FinancialSituationMemory, BaseLLMClient, SignalProcessor
  • State types use TypedDict with PascalCase: AgentState, InvestDebateState, RiskDebateState
  • Enums use PascalCase with UPPER_CASE members: AnalystType.MARKET, AnalystType.SOCIAL
  • Use UPPER_SNAKE_CASE: DEFAULT_CONFIG, TOOLS_CATEGORIES, VENDOR_METHODS, VENDOR_LIST
  • Module-level private constants use _UPPER_SNAKE_CASE: _PASSTHROUGH_KWARGS, _PROVIDER_CONFIG

Code Style

  • No automated formatter configured (no black, ruff, or yapf config files detected)
  • Indentation: 4 spaces (standard Python)
  • Line length varies; no enforced limit. Some lines exceed 120 characters, especially LLM prompt strings
  • Trailing commas used inconsistently
  • No linter configured (no flake8, pylint, ruff, or mypy config detected)
  • No pre-commit hooks
  • No CI/CD pipeline detected
  • Used selectively, not comprehensively
  • Present on class methods and factory function signatures: def create_llm_client(provider: str, model: str, ...) -> BaseLLMClient
  • Annotated types used extensively for LangChain tool parameters: Annotated[str, "ticker symbol"]
  • TypedDict used for agent state definitions in tradingagents/agents/utils/agent_states.py
  • Missing from most inner function closures and callback signatures

Import Organization

  • Wildcard imports used in some places: from tradingagents.agents import * in tradingagents/graph/setup.py and tradingagents/agents/utils/agent_states.py
  • Relative imports within packages: from .base_client import BaseLLMClient in tradingagents/llm_clients/
  • Absolute imports across packages: from tradingagents.dataflows.interface import route_to_vendor
  • __all__ lists defined in key __init__.py files: tradingagents/agents/__init__.py, tradingagents/llm_clients/__init__.py
  • None. All imports use full dotted paths.

Error Handling

  • Broad try/except Exception as e is the dominant pattern throughout the codebase
  • Error returns as formatted strings rather than raising exceptions: return f"Error retrieving fundamentals for {ticker}: {str(e)}" in tradingagents/dataflows/y_finance.py
  • This is intentional for LLM tool functions: errors become text the LLM can interpret
  • ValueError raised for invalid configuration: raise ValueError(f"Unsupported LLM provider: {provider}") in tradingagents/llm_clients/factory.py
  • Custom exception class: AlphaVantageRateLimitError in tradingagents/dataflows/alpha_vantage_common.py for vendor fallback logic
  • Fallback pattern in tradingagents/dataflows/interface.py: route_to_vendor() tries primary vendor, catches rate limit errors, falls back to alternatives
  • Silent error swallowing with print() in tradingagents/dataflows/y_finance.py: print(f"Error getting bulk stockstats data: {e}") followed by fallback logic
  • Raise ValueError for programming errors (bad config, invalid arguments)
  • Return error strings from data-fetching tool functions (these become LLM context)
  • Raise RuntimeError when all vendor fallbacks exhausted

Logging

  • Debug output via print(): print(f"Error getting stockstats indicator data...") in tradingagents/dataflows/y_finance.py
  • Rich console for CLI user-facing output: console = Console() with console.print() in cli/main.py and cli/utils.py
  • No log levels, no log files, no structured log format

Agent/Node Design Pattern

  • Analyst nodes: create_*_analyst(llm) - take only LLM, use tool-calling
  • Researcher/manager nodes: create_*(llm, memory) - take LLM + memory for reflection
  • Trader node: uses functools.partial to bind name: return functools.partial(trader_node, name="Trader")
  • All nodes return a dict updating parts of AgentState
  • Analyst nodes return {"messages": [result], "<type>_report": report}
  • Debate nodes return {"investment_debate_state": {...}} or {"risk_debate_state": {...}}

LLM Prompt Construction

Configuration Pattern

  • tradingagents/dataflows/config.py holds a module-level _config dict
  • set_config() and get_config() provide access
  • DEFAULT_CONFIG in tradingagents/default_config.py provides defaults
  • Config is a plain dict, not a dataclass or Pydantic model

Module Design

  • Key __init__.py files define __all__ lists for controlled exports
  • tradingagents/agents/__init__.py re-exports all agent factory functions
  • tradingagents/llm_clients/__init__.py exports BaseLLMClient and create_llm_client
  • tradingagents/agents/__init__.py serves as a barrel file aggregating all agent creators
  • tradingagents/dataflows/interface.py acts as the routing interface for all data operations

Docstrings

  • Present on classes and public methods, especially in tradingagents/graph/ and tradingagents/llm_clients/
  • Google-style docstrings with Args: and Returns: sections: see tradingagents/llm_clients/factory.py, tradingagents/graph/trading_graph.py
  • Missing from most inner closure functions and some utility functions
  • Tool functions use docstrings as LLM-readable descriptions (LangChain @tool convention)

Architecture

Pattern Overview

  • Stateful DAG execution via LangGraph StateGraph with a single shared AgentState
  • Factory-function pattern: every agent is created by a create_*() function that returns a closure
  • Two debate loops (investment + risk) with configurable round limits
  • Vendor-abstracted data layer with pluggable providers (yfinance, Alpha Vantage)
  • BM25-based memory system for reflection/learning across runs
  • Two LLM tiers: "quick think" (analysts, researchers, debators) and "deep think" (managers)

Layers

  • Purpose: Interactive terminal interface for configuring and running analyses
  • Location: cli/
  • Contains: Typer app, Rich UI rendering, interactive prompts, stats tracking
  • Depends on: tradingagents.graph.trading_graph, tradingagents.default_config
  • Used by: End users via tradingagents CLI command
  • Purpose: Constructs, configures, and executes the LangGraph agent workflow
  • Location: tradingagents/graph/
  • Contains: Graph setup, state propagation, conditional routing, reflection, signal processing
  • Depends on: Agents layer, LLM clients layer, dataflows config
  • Used by: CLI layer, main.py script, any Python consumer
  • Purpose: Implements all LLM-powered agent behaviors as node functions
  • Location: tradingagents/agents/
  • Contains: Analyst nodes, researcher debate nodes, trader node, manager nodes, risk debator nodes
  • Depends on: LangChain prompts/tools, dataflows (via tool functions), memory system
  • Used by: Graph orchestration layer
  • Purpose: Retrieves and routes financial data from external providers
  • Location: tradingagents/dataflows/
  • Contains: Vendor-specific implementations (yfinance, Alpha Vantage), routing interface, caching
  • Depends on: External APIs (yfinance, Alpha Vantage), local filesystem cache
  • Used by: Agent tool functions in tradingagents/agents/utils/
  • Purpose: Abstracts LLM provider creation behind a factory pattern
  • Location: tradingagents/llm_clients/
  • Contains: Base client ABC, provider-specific clients (OpenAI, Anthropic, Google), factory
  • Depends on: LangChain provider packages (langchain-openai, langchain-anthropic, langchain-google-genai)
  • Used by: Graph orchestration layer (TradingAgentsGraph.__init__)

Data Flow

  • Single AgentState (extends LangGraph MessagesState) flows through the entire graph
  • AgentState contains: messages, company/date, 4 analyst reports, InvestDebateState, RiskDebateState, trader plan, final decision
  • InvestDebateState tracks bull/bear debate history and round count
  • RiskDebateState tracks aggressive/conservative/neutral debate history and round count
  • State is immutable within LangGraph; nodes return partial state dicts that get merged

Key Abstractions

  • Purpose: Create agent node callables with captured LLM and memory references
  • Examples: tradingagents/agents/analysts/market_analyst.py::create_market_analyst, tradingagents/agents/researchers/bull_researcher.py::create_bull_researcher, tradingagents/agents/trader/trader.py::create_trader
  • Pattern: Each create_*() function returns an inner function (closure) that takes state and returns a partial state dict
  • Purpose: Decouple agents from specific data providers
  • Examples: tradingagents/dataflows/interface.py::route_to_vendor, tradingagents/agents/utils/core_stock_tools.py::get_stock_data
  • Pattern: Tool functions (decorated with @tool) call route_to_vendor(method_name, *args), which resolves the configured vendor and calls the appropriate implementation. Supports automatic fallback on rate-limit errors.
  • Purpose: Create LLM instances for any supported provider via a single entry point
  • Examples: tradingagents/llm_clients/factory.py::create_llm_client
  • Pattern: Factory function maps provider string to client class; each client implements BaseLLMClient ABC with get_llm() and validate_model()
  • Purpose: Store and retrieve past trading reflections for agent learning
  • Examples: tradingagents/agents/utils/memory.py::FinancialSituationMemory
  • Pattern: BM25-based lexical similarity search over stored situation-recommendation pairs. No external API or embedding model required.

Entry Points

  • Location: main.py
  • Triggers: Direct script execution (python main.py)
  • Responsibilities: Creates TradingAgentsGraph with custom config, calls propagate(), prints decision
  • Location: cli/main.py
  • Triggers: tradingagents shell command (registered via pyproject.toml [project.scripts])
  • Responsibilities: Interactive wizard for selecting provider, models, analysts, depth; runs analysis with Rich live UI; displays progress and final report
  • Location: tradingagents/graph/trading_graph.py
  • Triggers: from tradingagents.graph.trading_graph import TradingAgentsGraph
  • Responsibilities: Programmatic usage as a Python library

Error Handling

  • Data vendor fallback: route_to_vendor() catches AlphaVantageRateLimitError and falls through to next vendor in chain (tradingagents/dataflows/interface.py)
  • Analyst validation: GraphSetup.setup_graph() raises ValueError if no analysts selected (tradingagents/graph/setup.py)
  • LLM provider validation: create_llm_client() raises ValueError for unsupported providers (tradingagents/llm_clients/factory.py)
  • No structured error handling within agent nodes; LLM failures propagate as exceptions

Cross-Cutting Concerns

GSD Workflow Enforcement

Before using Edit, Write, or other file-changing tools, start work through a GSD command so planning artifacts and execution context stay in sync.

Use these entry points:

  • /gsd:quick for small fixes, doc updates, and ad-hoc tasks
  • /gsd:debug for investigation and bug fixing
  • /gsd:execute-phase for planned phase work

Do not make direct repo edits outside a GSD workflow unless the user explicitly asks to bypass it.

Developer Profile

Profile not yet configured. Run /gsd:profile-user to generate your developer profile. This section is managed by generate-claude-profile -- do not edit manually.