mirror of
https://github.com/TauricResearch/TradingAgents.git
synced 2026-09-27 15:02:39 +03:00
- --ticker, --date and --analysts answer their steps, checked as the prompts check them; --save/--no-save and --show/--no-show answer the questions after the run - with no terminal, the run stops before it starts and names every flag or TRADINGAGENTS_* variable still needed; a missing API key and an announcement no longer wait for input - README shows an unattended run
147 lines
6.1 KiB
Python
147 lines
6.1 KiB
Python
import sys
|
|
|
|
import typer
|
|
|
|
from cli.display import console
|
|
from cli.run import run_analysis
|
|
from tradingagents.backtest import iter_grid, run_backtest, summarize
|
|
from tradingagents.default_config import DEFAULT_CONFIG
|
|
from tradingagents.portfolio import load_portfolio
|
|
|
|
# prompt_toolkit's win32 output module is importable only on Windows (it asserts
|
|
# the platform at import time), so gate on the platform rather than catching the
|
|
# failure — that way a genuinely broken prompt_toolkit on Windows still surfaces
|
|
# instead of silently disabling the handler below. Off Windows this stays an
|
|
# empty tuple, which `except` accepts and never matches (#1138).
|
|
if sys.platform == "win32": # pragma: no cover - platform dependent
|
|
from prompt_toolkit.output.win32 import NoConsoleScreenBufferError
|
|
|
|
_NO_CONSOLE_ERRORS: tuple[type[BaseException], ...] = (NoConsoleScreenBufferError,)
|
|
else:
|
|
_NO_CONSOLE_ERRORS = ()
|
|
|
|
app = typer.Typer(
|
|
name="TradingAgents",
|
|
help="TradingAgents CLI: Multi-Agents LLM Financial Trading Framework",
|
|
add_completion=True, # Enable shell completion
|
|
)
|
|
|
|
|
|
@app.callback(invoke_without_command=True)
|
|
def analyze(
|
|
ctx: typer.Context,
|
|
checkpoint: bool | None = typer.Option(
|
|
None,
|
|
"--checkpoint/--no-checkpoint",
|
|
help="Enable/disable checkpoint-resume (save state after each node so a "
|
|
"crashed run can resume). Omit to honor TRADINGAGENTS_CHECKPOINT_ENABLED.",
|
|
),
|
|
clear_checkpoints: bool = typer.Option(
|
|
False,
|
|
"--clear-checkpoints",
|
|
help="Delete all saved checkpoints before running (force fresh start).",
|
|
),
|
|
portfolio: str = typer.Option(
|
|
None,
|
|
"--portfolio",
|
|
help="JSON file with current holdings and cash, so the trader, risk and "
|
|
"portfolio agents size against your actual position.",
|
|
),
|
|
ticker: str = typer.Option(None, "--ticker", help="Ticker to analyze, e.g. NVDA or 0700.HK; skips the prompt"),
|
|
date: str = typer.Option(None, "--date", help="Analysis date, YYYY-MM-DD; skips the prompt"),
|
|
analysts: str = typer.Option(
|
|
None, "--analysts", help="Comma-separated analysts, e.g. market,news; skips the prompt"
|
|
),
|
|
save: bool | None = typer.Option(
|
|
None, "--save/--no-save", help="Save the report under results_dir without asking"
|
|
),
|
|
show: bool | None = typer.Option(
|
|
None, "--show/--no-show", help="Show the full report at the end without asking"
|
|
),
|
|
):
|
|
"""Run an analysis. This is what a bare `tradingagents` does.
|
|
|
|
Flags answer their questions; with provider, models, depth and language also
|
|
set through TRADINGAGENTS_* variables, the run asks nothing.
|
|
"""
|
|
if ctx.invoked_subcommand is not None:
|
|
return
|
|
if clear_checkpoints:
|
|
from tradingagents.graph.checkpointer import clear_all_checkpoints
|
|
n = clear_all_checkpoints(DEFAULT_CONFIG["data_cache_dir"])
|
|
console.print(f"[yellow]Cleared {n} checkpoint(s).[/yellow]")
|
|
portfolio_context = None
|
|
if portfolio:
|
|
try:
|
|
portfolio_context = load_portfolio(portfolio)
|
|
except ValueError as exc:
|
|
console.print(f"[red]{exc}[/red]")
|
|
raise typer.Exit(code=1) from None
|
|
|
|
try:
|
|
flags = {"ticker": ticker, "date": date, "analysts": analysts, "save": save, "show": show}
|
|
run_analysis(checkpoint=checkpoint, portfolio=portfolio_context, flags=flags)
|
|
except _NO_CONSOLE_ERRORS:
|
|
# A terminal with no console buffer cannot host the interactive prompts.
|
|
# Emit one actionable line on stderr instead of a prompt_toolkit
|
|
# traceback; plain text, since rich may not render here either (#1138).
|
|
typer.echo(
|
|
"Error: no Windows console available. The interactive CLI needs a real "
|
|
"console buffer — run it from Windows Terminal, PowerShell, or cmd.exe "
|
|
"rather than a piped or embedded terminal.",
|
|
err=True,
|
|
)
|
|
raise typer.Exit(code=1) from None
|
|
|
|
|
|
@app.command()
|
|
def backtest(
|
|
tickers: str = typer.Argument(..., help="Comma-separated tickers, e.g. NVDA,AAPL"),
|
|
start: str = typer.Option(..., "--start", help="First analysis date, YYYY-MM-DD"),
|
|
end: str = typer.Option(..., "--end", help="Last analysis date, YYYY-MM-DD"),
|
|
every: int = typer.Option(7, "--every", help="Days between analysis dates"),
|
|
analysts: str = typer.Option(
|
|
None, "--analysts", help="Comma-separated analysts to run; omit for all four"
|
|
),
|
|
asset_type: str = typer.Option("stock", "--asset-type", help="stock or crypto"),
|
|
portfolio: str = typer.Option(
|
|
None, "--portfolio", help="JSON file with holdings and cash, held constant across the grid"
|
|
),
|
|
run_id: str = typer.Option(
|
|
None, "--run-id", help="Continue an earlier sweep: its cells are skipped and its log reused"
|
|
),
|
|
):
|
|
"""Score past decisions over a grid of tickers and dates."""
|
|
|
|
try:
|
|
dates = iter_grid(start, end, every)
|
|
book = load_portfolio(portfolio) if portfolio else None
|
|
except ValueError as exc:
|
|
console.print(f"[red]{exc}[/red]")
|
|
raise typer.Exit(code=1) from None
|
|
|
|
names = [t.strip() for t in tickers.split(",") if t.strip()]
|
|
if not names:
|
|
console.print("[red]No ticker to analyze; pass them comma-separated, e.g. NVDA,AAPL[/red]")
|
|
raise typer.Exit(code=1)
|
|
|
|
kwargs = {"asset_type": asset_type, "portfolio": book, "run_id": run_id}
|
|
if analysts:
|
|
kwargs["selected_analysts"] = [a.strip().lower() for a in analysts.split(",") if a.strip()]
|
|
|
|
try:
|
|
result = run_backtest(names, dates, DEFAULT_CONFIG, **kwargs)
|
|
except Exception as exc: # a missing key or an unknown analyst is a setup error
|
|
console.print(f"[red]{exc}[/red]")
|
|
raise typer.Exit(code=1) from None
|
|
console.print(summarize(result).render())
|
|
console.print(f"\nRan {result.cells_run} cells, skipped {result.skipped}. Log: {result.log_path}")
|
|
for ticker, date, reason in result.failures:
|
|
console.print(f"[yellow]failed:[/yellow] {ticker} {date}: {reason}")
|
|
for ticker, reason in result.settlement_failures:
|
|
console.print(f"[yellow]unsettled:[/yellow] {ticker}: {reason}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
app()
|