From 4a3aa5ca3ce14157363e13578a1a02bd54579f56 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 21 Mar 2026 22:33:06 +0000 Subject: [PATCH] refactor: centralize env loading in default_config.py; fix .env.example Co-authored-by: aguzererler <6199053+aguzererler@users.noreply.github.com> Agent-Logs-Url: https://github.com/aguzererler/TradingAgents/sessions/b62cf290-b389-45bf-b644-08b2360a1f76 --- .env.example | 29 +++++++++++++++------ cli/main.py | 7 +++-- tradingagents/default_config.py | 14 ++++++++++ tradingagents/portfolio/config.py | 43 +++++++------------------------ 4 files changed, 49 insertions(+), 44 deletions(-) diff --git a/.env.example b/.env.example index 8575010d..f8b4febc 100644 --- a/.env.example +++ b/.env.example @@ -11,15 +11,13 @@ ALPHA_VANTAGE_API_KEY= # Free at https://finnhub.io — required for earnings/economic calendars and insider transactions FINNHUB_API_KEY= -TRADINGAGENTS_RESULTS_DIR=./my_results -TRADINGAGENTS_MAX_DEBATE_ROUNDS=2 - -#TRADINGAGENTS_VENDOR_SCANNER_DATA=alpha_vantage - # ── Configuration overrides ────────────────────────────────────────── # Any setting in DEFAULT_CONFIG (tradingagents/default_config.py) can be # overridden with a TRADINGAGENTS_ environment variable. -# Unset or empty values are ignored (the hardcoded default is kept). +# Unset or empty values are ignored — the hardcoded default is kept. +# +# This file is the single source of truth for runtime configuration. +# Copy this file to .env and fill in the values you want to override. # ── General ────────────────────────────────────────────────────────── # TRADINGAGENTS_RESULTS_DIR=./results @@ -59,8 +57,8 @@ TRADINGAGENTS_MAX_DEBATE_ROUNDS=2 # TRADINGAGENTS_QUICK_THINK_OPENAI_REASONING_EFFORT= # ── Debate & discussion settings ───────────────────────────────────── -# TRADINGAGENTS_MAX_DEBATE_ROUNDS=1 # bull/bear investment debate rounds (1–5) -# TRADINGAGENTS_MAX_RISK_DISCUSS_ROUNDS=1 # risk analyst discussion rounds (1–5) +# TRADINGAGENTS_MAX_DEBATE_ROUNDS=2 # bull/bear investment debate rounds (1–5) +# TRADINGAGENTS_MAX_RISK_DISCUSS_ROUNDS=2 # risk analyst discussion rounds (1–5) # TRADINGAGENTS_MAX_RECUR_LIMIT=100 # LangGraph recursion limit # ── Google NotebookLM sync (optional) ──────────────────────────────── @@ -75,3 +73,18 @@ TRADINGAGENTS_MAX_DEBATE_ROUNDS=2 # TRADINGAGENTS_VENDOR_NEWS_DATA=yfinance # TRADINGAGENTS_VENDOR_SCANNER_DATA=yfinance # TRADINGAGENTS_VENDOR_CALENDAR_DATA=finnhub + +# ── Portfolio Manager ───────────────────────────────────────────────── +# PostgreSQL connection string for Supabase (required for portfolio commands) +# SUPABASE_CONNECTION_STRING=postgresql://postgres.:@aws-1-.pooler.supabase.com:6543/postgres + +# Portfolio data directory (where JSON reports are stored) +# TRADINGAGENTS_PORTFOLIO_DATA_DIR=reports + +# Portfolio constraint overrides +# TRADINGAGENTS_PM_MAX_POSITIONS=15 # maximum number of open positions +# TRADINGAGENTS_PM_MAX_POSITION_PCT=0.15 # max single position as fraction of portfolio +# TRADINGAGENTS_PM_MAX_SECTOR_PCT=0.35 # max sector concentration +# TRADINGAGENTS_PM_MIN_CASH_PCT=0.05 # minimum cash reserve +# TRADINGAGENTS_PM_DEFAULT_BUDGET=100000.0 # starting cash budget (USD) + diff --git a/cli/main.py b/cli/main.py index b02eaf4c..ab956fe6 100644 --- a/cli/main.py +++ b/cli/main.py @@ -8,8 +8,11 @@ from functools import wraps from rich.console import Console from dotenv import load_dotenv -# Load environment variables from .env file. -# Checks CWD first, then falls back to project root (relative to this script). +# Load API keys (OPENAI_API_KEY, GOOGLE_API_KEY, etc.) from the .env file +# before any network call is made. tradingagents.default_config also calls +# load_dotenv() at import time (for TRADINGAGENTS_* config vars), so these +# two calls are a defence-in-depth safety net for the CLI entry point. +# Order: CWD .env first, then the project-root .env as a fallback. load_dotenv() load_dotenv(Path(__file__).resolve().parent.parent / ".env") from rich.panel import Panel diff --git a/tradingagents/default_config.py b/tradingagents/default_config.py index 75cc5ab3..254eed5a 100644 --- a/tradingagents/default_config.py +++ b/tradingagents/default_config.py @@ -18,6 +18,9 @@ def _env(key: str, default=None): ``TRADINGAGENTS_MID_THINK_LLM=`` in a ``.env`` file is treated the same as not setting it at all (preserving the ``None`` semantics for "fall back to the parent setting"). + + This is the single source of truth for config env-var reading. + Import and reuse this helper instead of duplicating it elsewhere. """ val = os.getenv(f"TRADINGAGENTS_{key.upper()}") if not val: # None or "" @@ -36,6 +39,17 @@ def _env_int(key: str, default=None): return default +def _env_float(key: str, default=None): + """Like :func:`_env` but coerces the value to ``float``.""" + val = _env(key) + if val is None: + return default + try: + return float(val) + except (ValueError, TypeError): + return default + + DEFAULT_CONFIG = { "project_dir": os.path.abspath(os.path.join(os.path.dirname(__file__), ".")), "results_dir": _env("RESULTS_DIR", "./reports"), diff --git a/tradingagents/portfolio/config.py b/tradingagents/portfolio/config.py index d8293e49..4a4df90d 100644 --- a/tradingagents/portfolio/config.py +++ b/tradingagents/portfolio/config.py @@ -3,6 +3,10 @@ Integrates with the existing ``tradingagents/default_config.py`` pattern, reading all portfolio settings from ``TRADINGAGENTS_`` env vars. +All env-var reading is delegated to the shared helpers in +``tradingagents.default_config`` — that module is the single entry point +for .env loading and the ``_env*`` helper functions. + Usage:: from tradingagents.portfolio.config import get_portfolio_config, validate_config @@ -16,40 +20,11 @@ from __future__ import annotations import os -from dotenv import load_dotenv - -load_dotenv() - - -def _env(key: str, default=None): - """Read ``TRADINGAGENTS_`` from the environment. - - Matches the convention in ``tradingagents/default_config.py``. - """ - val = os.getenv(f"TRADINGAGENTS_{key.upper()}") - if not val: - return default - return val - - -def _env_float(key: str, default=None): - val = _env(key) - if val is None: - return default - try: - return float(val) - except (ValueError, TypeError): - return default - - -def _env_int(key: str, default=None): - val = _env(key) - if val is None: - return default - try: - return int(val) - except (ValueError, TypeError): - return default +# Importing default_config triggers its module-level load_dotenv() calls, +# which loads the .env file (CWD first, then project root) before we read +# any TRADINGAGENTS_* variables below. This is the single source of truth +# for .env loading — no separate load_dotenv() call needed here. +from tradingagents.default_config import _env, _env_float, _env_int PORTFOLIO_CONFIG: dict = {