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.lockresolution markers) - uv (primary -
uv.lockpresent at project root) - pip/setuptools (build backend,
pyproject.tomlusessetuptools>=61.0) - Lockfile:
uv.lockpresent
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 LangGraphStateGraphinstances compiled and executed via.stream()/.invoke()langchain-core >=0.3.81- ProvidesBaseCallbackHandler, message types (AIMessage), and tool abstractions used throughoutyfinance >=0.2.63- Default financial data vendor for stock prices, fundamentals, news, insider transactionsbacktrader >=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.envfiles (main.py,cli/main.py)tqdm >=4.67.1- Progress barspytz >=2025.2- Timezone handling
Configuration
.envfile present - loaded viapython-dotenvat startup.env.exampledocuments required API keys:OPENAI_API_KEY,GOOGLE_API_KEY,ANTHROPIC_API_KEY,XAI_API_KEY,OPENROUTER_API_KEYALPHA_VANTAGE_API_KEY- Required when using Alpha Vantage data vendorTRADINGAGENTS_RESULTS_DIR- Optional, defaults to./resultstradingagents/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 dataeval_results/{ticker}/- Logged trading states as JSONresults/- Trade results output directoryredis >=6.2.0declared 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.pyfor 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_casefor 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_casefor all variables:curr_situation,past_memory_str,trade_date - Abbreviations are common and accepted:
llm,curr_date,curr_date_dt - Config keys use
snake_casestrings:"deep_think_llm","max_debate_rounds","data_vendors" - Use
PascalCase:TradingAgentsGraph,FinancialSituationMemory,BaseLLMClient,SignalProcessor - State types use
TypedDictwithPascalCase:AgentState,InvestDebateState,RiskDebateState - Enums use
PascalCasewithUPPER_CASEmembers: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 Annotatedtypes used extensively for LangChain tool parameters:Annotated[str, "ticker symbol"]TypedDictused for agent state definitions intradingagents/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 *intradingagents/graph/setup.pyandtradingagents/agents/utils/agent_states.py - Relative imports within packages:
from .base_client import BaseLLMClientintradingagents/llm_clients/ - Absolute imports across packages:
from tradingagents.dataflows.interface import route_to_vendor __all__lists defined in key__init__.pyfiles:tradingagents/agents/__init__.py,tradingagents/llm_clients/__init__.py- None. All imports use full dotted paths.
Error Handling
- Broad
try/except Exception as eis the dominant pattern throughout the codebase - Error returns as formatted strings rather than raising exceptions:
return f"Error retrieving fundamentals for {ticker}: {str(e)}"intradingagents/dataflows/y_finance.py - This is intentional for LLM tool functions: errors become text the LLM can interpret
ValueErrorraised for invalid configuration:raise ValueError(f"Unsupported LLM provider: {provider}")intradingagents/llm_clients/factory.py- Custom exception class:
AlphaVantageRateLimitErrorintradingagents/dataflows/alpha_vantage_common.pyfor 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()intradingagents/dataflows/y_finance.py:print(f"Error getting bulk stockstats data: {e}")followed by fallback logic - Raise
ValueErrorfor programming errors (bad config, invalid arguments) - Return error strings from data-fetching tool functions (these become LLM context)
- Raise
RuntimeErrorwhen all vendor fallbacks exhausted
Logging
- Debug output via
print():print(f"Error getting stockstats indicator data...")intradingagents/dataflows/y_finance.py - Rich console for CLI user-facing output:
console = Console()withconsole.print()incli/main.pyandcli/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.partialto 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.pyholds a module-level_configdictset_config()andget_config()provide accessDEFAULT_CONFIGintradingagents/default_config.pyprovides defaults- Config is a plain
dict, not a dataclass or Pydantic model
Module Design
- Key
__init__.pyfiles define__all__lists for controlled exports tradingagents/agents/__init__.pyre-exports all agent factory functionstradingagents/llm_clients/__init__.pyexportsBaseLLMClientandcreate_llm_clienttradingagents/agents/__init__.pyserves as a barrel file aggregating all agent creatorstradingagents/dataflows/interface.pyacts as the routing interface for all data operations
Docstrings
- Present on classes and public methods, especially in
tradingagents/graph/andtradingagents/llm_clients/ - Google-style docstrings with
Args:andReturns:sections: seetradingagents/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
@toolconvention)
Architecture
Pattern Overview
- Stateful DAG execution via LangGraph
StateGraphwith a single sharedAgentState - 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
tradingagentsCLI 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.pyscript, 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 LangGraphMessagesState) flows through the entire graph AgentStatecontains: messages, company/date, 4 analyst reports,InvestDebateState,RiskDebateState, trader plan, final decisionInvestDebateStatetracks bull/bear debate history and round countRiskDebateStatetracks 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 takesstateand 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) callroute_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
BaseLLMClientABC withget_llm()andvalidate_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
TradingAgentsGraphwith custom config, callspropagate(), prints decision - Location:
cli/main.py - Triggers:
tradingagentsshell command (registered viapyproject.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()catchesAlphaVantageRateLimitErrorand falls through to next vendor in chain (tradingagents/dataflows/interface.py) - Analyst validation:
GraphSetup.setup_graph()raisesValueErrorif no analysts selected (tradingagents/graph/setup.py) - LLM provider validation:
create_llm_client()raisesValueErrorfor 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:quickfor small fixes, doc updates, and ad-hoc tasks/gsd:debugfor investigation and bug fixing/gsd:execute-phasefor 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-userto generate your developer profile. This section is managed bygenerate-claude-profile-- do not edit manually.