mirror of
https://github.com/TauricResearch/TradingAgents.git
synced 2026-05-02 23:13:11 +03:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
551fd7f074 | ||
|
|
b0f9d180f9 | ||
|
|
9cc283ac22 | ||
|
|
fe9c8d5d31 | ||
|
|
eec6ca4b53 | ||
|
|
3642f5917c | ||
|
|
907bc8022a | ||
|
|
8a60662070 | ||
|
|
f047f26df0 | ||
|
|
35856ff33e | ||
|
|
5fec171a1e | ||
|
|
50c82a25b5 | ||
|
|
8b3068d091 | ||
|
|
66a02b3193 | ||
|
|
e9470b69c4 |
@@ -1 +0,0 @@
|
|||||||
3.10
|
|
||||||
@@ -462,7 +462,7 @@ def update_display(layout, spinner_text=None, stats_handler=None, start_time=Non
|
|||||||
def get_user_selections():
|
def get_user_selections():
|
||||||
"""Get all user selections before starting the analysis display."""
|
"""Get all user selections before starting the analysis display."""
|
||||||
# Display ASCII art welcome message
|
# Display ASCII art welcome message
|
||||||
with open("./cli/static/welcome.txt", "r") as f:
|
with open("./cli/static/welcome.txt", "r", encoding="utf-8") as f:
|
||||||
welcome_ascii = f.read()
|
welcome_ascii = f.read()
|
||||||
|
|
||||||
# Create welcome box content
|
# Create welcome box content
|
||||||
@@ -948,7 +948,7 @@ def run_analysis():
|
|||||||
func(*args, **kwargs)
|
func(*args, **kwargs)
|
||||||
timestamp, message_type, content = obj.messages[-1]
|
timestamp, message_type, content = obj.messages[-1]
|
||||||
content = content.replace("\n", " ") # Replace newlines with spaces
|
content = content.replace("\n", " ") # Replace newlines with spaces
|
||||||
with open(log_file, "a") as f:
|
with open(log_file, "a", encoding="utf-8") as f:
|
||||||
f.write(f"{timestamp} [{message_type}] {content}\n")
|
f.write(f"{timestamp} [{message_type}] {content}\n")
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
@@ -959,7 +959,7 @@ def run_analysis():
|
|||||||
func(*args, **kwargs)
|
func(*args, **kwargs)
|
||||||
timestamp, tool_name, args = obj.tool_calls[-1]
|
timestamp, tool_name, args = obj.tool_calls[-1]
|
||||||
args_str = ", ".join(f"{k}={v}" for k, v in args.items())
|
args_str = ", ".join(f"{k}={v}" for k, v in args.items())
|
||||||
with open(log_file, "a") as f:
|
with open(log_file, "a", encoding="utf-8") as f:
|
||||||
f.write(f"{timestamp} [Tool Call] {tool_name}({args_str})\n")
|
f.write(f"{timestamp} [Tool Call] {tool_name}({args_str})\n")
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
@@ -972,7 +972,7 @@ def run_analysis():
|
|||||||
content = obj.report_sections[section_name]
|
content = obj.report_sections[section_name]
|
||||||
if content:
|
if content:
|
||||||
file_name = f"{section_name}.md"
|
file_name = f"{section_name}.md"
|
||||||
with open(report_dir / file_name, "w") as f:
|
with open(report_dir / file_name, "w", encoding="utf-8") as f:
|
||||||
f.write(content)
|
f.write(content)
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|||||||
53
cli/utils.py
53
cli/utils.py
@@ -1,8 +1,12 @@
|
|||||||
import questionary
|
import questionary
|
||||||
from typing import List, Optional, Tuple, Dict
|
from typing import List, Optional, Tuple, Dict
|
||||||
|
|
||||||
|
from rich.console import Console
|
||||||
|
|
||||||
from cli.models import AnalystType
|
from cli.models import AnalystType
|
||||||
|
|
||||||
|
console = Console()
|
||||||
|
|
||||||
ANALYST_ORDER = [
|
ANALYST_ORDER = [
|
||||||
("Market Analyst", AnalystType.MARKET),
|
("Market Analyst", AnalystType.MARKET),
|
||||||
("Social Media Analyst", AnalystType.SOCIAL),
|
("Social Media Analyst", AnalystType.SOCIAL),
|
||||||
@@ -126,30 +130,30 @@ def select_shallow_thinking_agent(provider) -> str:
|
|||||||
"""Select shallow thinking llm engine using an interactive selection."""
|
"""Select shallow thinking llm engine using an interactive selection."""
|
||||||
|
|
||||||
# Define shallow thinking llm engine options with their corresponding model names
|
# Define shallow thinking llm engine options with their corresponding model names
|
||||||
|
# Ordering: medium → light → heavy (balanced first for quick tasks)
|
||||||
|
# Within same tier, newer models first
|
||||||
SHALLOW_AGENT_OPTIONS = {
|
SHALLOW_AGENT_OPTIONS = {
|
||||||
"openai": [
|
"openai": [
|
||||||
("GPT-5 Mini - Cost-optimized reasoning", "gpt-5-mini"),
|
("GPT-5 Mini - Balanced speed, cost, and capability", "gpt-5-mini"),
|
||||||
("GPT-5 Nano - Ultra-fast, high-throughput", "gpt-5-nano"),
|
("GPT-5 Nano - High-throughput, simple tasks", "gpt-5-nano"),
|
||||||
("GPT-5.2 - Latest flagship", "gpt-5.2"),
|
("GPT-5.4 - Latest frontier, 1M context", "gpt-5.4"),
|
||||||
("GPT-5.1 - Flexible reasoning", "gpt-5.1"),
|
("GPT-4.1 - Smartest non-reasoning model", "gpt-4.1"),
|
||||||
("GPT-4.1 - Smartest non-reasoning, 1M context", "gpt-4.1"),
|
|
||||||
],
|
],
|
||||||
"anthropic": [
|
"anthropic": [
|
||||||
("Claude Haiku 4.5 - Fast + extended thinking", "claude-haiku-4-5"),
|
("Claude Sonnet 4.6 - Best speed and intelligence balance", "claude-sonnet-4-6"),
|
||||||
("Claude Sonnet 4.5 - Best for agents/coding", "claude-sonnet-4-5"),
|
("Claude Haiku 4.5 - Fast, near-instant responses", "claude-haiku-4-5"),
|
||||||
("Claude Sonnet 4 - High-performance", "claude-sonnet-4-20250514"),
|
("Claude Sonnet 4.5 - Agents and coding", "claude-sonnet-4-5"),
|
||||||
],
|
],
|
||||||
"google": [
|
"google": [
|
||||||
("Gemini 3 Flash - Next-gen fast", "gemini-3-flash-preview"),
|
("Gemini 3 Flash - Next-gen fast", "gemini-3-flash-preview"),
|
||||||
("Gemini 2.5 Flash - Balanced, recommended", "gemini-2.5-flash"),
|
("Gemini 2.5 Flash - Balanced, stable", "gemini-2.5-flash"),
|
||||||
("Gemini 3 Pro - Reasoning-first", "gemini-3-pro-preview"),
|
("Gemini 3.1 Flash Lite - Most cost-efficient", "gemini-3.1-flash-lite-preview"),
|
||||||
("Gemini 2.5 Flash Lite - Fast, low-cost", "gemini-2.5-flash-lite"),
|
("Gemini 2.5 Flash Lite - Fast, low-cost", "gemini-2.5-flash-lite"),
|
||||||
],
|
],
|
||||||
"xai": [
|
"xai": [
|
||||||
("Grok 4.1 Fast (Non-Reasoning) - Speed optimized, 2M ctx", "grok-4-1-fast-non-reasoning"),
|
("Grok 4.1 Fast (Non-Reasoning) - Speed optimized, 2M ctx", "grok-4-1-fast-non-reasoning"),
|
||||||
("Grok 4 Fast (Non-Reasoning) - Speed optimized", "grok-4-fast-non-reasoning"),
|
("Grok 4 Fast (Non-Reasoning) - Speed optimized", "grok-4-fast-non-reasoning"),
|
||||||
("Grok 4.1 Fast (Reasoning) - High-performance, 2M ctx", "grok-4-1-fast-reasoning"),
|
("Grok 4.1 Fast (Reasoning) - High-performance, 2M ctx", "grok-4-1-fast-reasoning"),
|
||||||
("Grok 4 Fast (Reasoning) - High-performance", "grok-4-fast-reasoning"),
|
|
||||||
],
|
],
|
||||||
"openrouter": [
|
"openrouter": [
|
||||||
("NVIDIA Nemotron 3 Nano 30B (free)", "nvidia/nemotron-3-nano-30b-a3b:free"),
|
("NVIDIA Nemotron 3 Nano 30B (free)", "nvidia/nemotron-3-nano-30b-a3b:free"),
|
||||||
@@ -191,33 +195,32 @@ def select_deep_thinking_agent(provider) -> str:
|
|||||||
"""Select deep thinking llm engine using an interactive selection."""
|
"""Select deep thinking llm engine using an interactive selection."""
|
||||||
|
|
||||||
# Define deep thinking llm engine options with their corresponding model names
|
# Define deep thinking llm engine options with their corresponding model names
|
||||||
|
# Ordering: heavy → medium → light (most capable first for deep tasks)
|
||||||
|
# Within same tier, newer models first
|
||||||
DEEP_AGENT_OPTIONS = {
|
DEEP_AGENT_OPTIONS = {
|
||||||
"openai": [
|
"openai": [
|
||||||
("GPT-5.2 - Latest flagship", "gpt-5.2"),
|
("GPT-5.4 - Latest frontier, 1M context", "gpt-5.4"),
|
||||||
("GPT-5.1 - Flexible reasoning", "gpt-5.1"),
|
("GPT-5.2 - Strong reasoning, cost-effective", "gpt-5.2"),
|
||||||
("GPT-5 - Advanced reasoning", "gpt-5"),
|
("GPT-5 Mini - Balanced speed, cost, and capability", "gpt-5-mini"),
|
||||||
("GPT-4.1 - Smartest non-reasoning, 1M context", "gpt-4.1"),
|
("GPT-5.4 Pro - Most capable, expensive ($30/$180 per 1M tokens)", "gpt-5.4-pro"),
|
||||||
("GPT-5 Mini - Cost-optimized reasoning", "gpt-5-mini"),
|
|
||||||
("GPT-5 Nano - Ultra-fast, high-throughput", "gpt-5-nano"),
|
|
||||||
],
|
],
|
||||||
"anthropic": [
|
"anthropic": [
|
||||||
("Claude Sonnet 4.5 - Best for agents/coding", "claude-sonnet-4-5"),
|
("Claude Opus 4.6 - Most intelligent, agents and coding", "claude-opus-4-6"),
|
||||||
("Claude Opus 4.5 - Premium, max intelligence", "claude-opus-4-5"),
|
("Claude Opus 4.5 - Premium, max intelligence", "claude-opus-4-5"),
|
||||||
("Claude Opus 4.1 - Most capable model", "claude-opus-4-1-20250805"),
|
("Claude Sonnet 4.6 - Best speed and intelligence balance", "claude-sonnet-4-6"),
|
||||||
("Claude Haiku 4.5 - Fast + extended thinking", "claude-haiku-4-5"),
|
("Claude Sonnet 4.5 - Agents and coding", "claude-sonnet-4-5"),
|
||||||
("Claude Sonnet 4 - High-performance", "claude-sonnet-4-20250514"),
|
|
||||||
],
|
],
|
||||||
"google": [
|
"google": [
|
||||||
("Gemini 3 Pro - Reasoning-first", "gemini-3-pro-preview"),
|
("Gemini 3.1 Pro - Reasoning-first, complex workflows", "gemini-3.1-pro-preview"),
|
||||||
("Gemini 3 Flash - Next-gen fast", "gemini-3-flash-preview"),
|
("Gemini 3 Flash - Next-gen fast", "gemini-3-flash-preview"),
|
||||||
("Gemini 2.5 Flash - Balanced, recommended", "gemini-2.5-flash"),
|
("Gemini 2.5 Pro - Stable pro model", "gemini-2.5-pro"),
|
||||||
|
("Gemini 2.5 Flash - Balanced, stable", "gemini-2.5-flash"),
|
||||||
],
|
],
|
||||||
"xai": [
|
"xai": [
|
||||||
|
("Grok 4 - Flagship model", "grok-4-0709"),
|
||||||
("Grok 4.1 Fast (Reasoning) - High-performance, 2M ctx", "grok-4-1-fast-reasoning"),
|
("Grok 4.1 Fast (Reasoning) - High-performance, 2M ctx", "grok-4-1-fast-reasoning"),
|
||||||
("Grok 4 Fast (Reasoning) - High-performance", "grok-4-fast-reasoning"),
|
("Grok 4 Fast (Reasoning) - High-performance", "grok-4-fast-reasoning"),
|
||||||
("Grok 4 - Flagship model", "grok-4-0709"),
|
|
||||||
("Grok 4.1 Fast (Non-Reasoning) - Speed optimized, 2M ctx", "grok-4-1-fast-non-reasoning"),
|
("Grok 4.1 Fast (Non-Reasoning) - Speed optimized, 2M ctx", "grok-4-1-fast-non-reasoning"),
|
||||||
("Grok 4 Fast (Non-Reasoning) - Speed optimized", "grok-4-fast-non-reasoning"),
|
|
||||||
],
|
],
|
||||||
"openrouter": [
|
"openrouter": [
|
||||||
("Z.AI GLM 4.5 Air (free)", "z-ai/glm-4.5-air:free"),
|
("Z.AI GLM 4.5 Air (free)", "z-ai/glm-4.5-air:free"),
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
|
[build-system]
|
||||||
|
requires = ["setuptools>=61.0"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "tradingagents"
|
name = "tradingagents"
|
||||||
version = "0.1.0"
|
version = "0.2.1"
|
||||||
description = "Add your description here"
|
description = "TradingAgents: Multi-Agents LLM Financial Trading Framework"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"langchain-core>=0.3.81",
|
||||||
"backtrader>=1.9.78.123",
|
"backtrader>=1.9.78.123",
|
||||||
"chainlit>=2.5.5",
|
|
||||||
"langchain-anthropic>=0.3.15",
|
"langchain-anthropic>=0.3.15",
|
||||||
"langchain-experimental>=0.3.4",
|
"langchain-experimental>=0.3.4",
|
||||||
"langchain-google-genai>=2.1.5",
|
"langchain-google-genai>=2.1.5",
|
||||||
@@ -27,3 +31,9 @@ dependencies = [
|
|||||||
"typing-extensions>=4.14.0",
|
"typing-extensions>=4.14.0",
|
||||||
"yfinance>=0.2.63",
|
"yfinance>=0.2.63",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[project.scripts]
|
||||||
|
tradingagents = "cli.main:app"
|
||||||
|
|
||||||
|
[tool.setuptools.packages.find]
|
||||||
|
include = ["tradingagents*", "cli*"]
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
typing-extensions
|
typing-extensions
|
||||||
|
langchain-core
|
||||||
langchain-openai
|
langchain-openai
|
||||||
langchain-experimental
|
langchain-experimental
|
||||||
pandas
|
pandas
|
||||||
@@ -13,7 +14,6 @@ requests
|
|||||||
tqdm
|
tqdm
|
||||||
pytz
|
pytz
|
||||||
redis
|
redis
|
||||||
chainlit
|
|
||||||
rich
|
rich
|
||||||
typer
|
typer
|
||||||
questionary
|
questionary
|
||||||
|
|||||||
43
setup.py
43
setup.py
@@ -1,43 +0,0 @@
|
|||||||
"""
|
|
||||||
Setup script for the TradingAgents package.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from setuptools import setup, find_packages
|
|
||||||
|
|
||||||
setup(
|
|
||||||
name="tradingagents",
|
|
||||||
version="0.1.0",
|
|
||||||
description="Multi-Agents LLM Financial Trading Framework",
|
|
||||||
author="TradingAgents Team",
|
|
||||||
author_email="yijia.xiao@cs.ucla.edu",
|
|
||||||
url="https://github.com/TauricResearch",
|
|
||||||
packages=find_packages(),
|
|
||||||
install_requires=[
|
|
||||||
"langchain>=0.1.0",
|
|
||||||
"langchain-openai>=0.0.2",
|
|
||||||
"langchain-experimental>=0.0.40",
|
|
||||||
"langgraph>=0.0.20",
|
|
||||||
"numpy>=1.24.0",
|
|
||||||
"pandas>=2.0.0",
|
|
||||||
"praw>=7.7.0",
|
|
||||||
"stockstats>=0.5.4",
|
|
||||||
"yfinance>=0.2.31",
|
|
||||||
"typer>=0.9.0",
|
|
||||||
"rich>=13.0.0",
|
|
||||||
"questionary>=2.0.1",
|
|
||||||
],
|
|
||||||
python_requires=">=3.10",
|
|
||||||
entry_points={
|
|
||||||
"console_scripts": [
|
|
||||||
"tradingagents=cli.main:app",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
classifiers=[
|
|
||||||
"Development Status :: 3 - Alpha",
|
|
||||||
"Intended Audience :: Financial and Trading Industry",
|
|
||||||
"License :: OSI Approved :: Apache Software License",
|
|
||||||
"Programming Language :: Python :: 3",
|
|
||||||
"Programming Language :: Python :: 3.10",
|
|
||||||
"Topic :: Office/Business :: Financial :: Investment",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
0
tradingagents/__init__.py
Normal file
0
tradingagents/__init__.py
Normal file
@@ -11,7 +11,7 @@ def create_risk_manager(llm, memory):
|
|||||||
risk_debate_state = state["risk_debate_state"]
|
risk_debate_state = state["risk_debate_state"]
|
||||||
market_research_report = state["market_report"]
|
market_research_report = state["market_report"]
|
||||||
news_report = state["news_report"]
|
news_report = state["news_report"]
|
||||||
fundamentals_report = state["news_report"]
|
fundamentals_report = state["fundamentals_report"]
|
||||||
sentiment_report = state["sentiment_report"]
|
sentiment_report = state["sentiment_report"]
|
||||||
trader_plan = state["investment_plan"]
|
trader_plan = state["investment_plan"]
|
||||||
|
|
||||||
|
|||||||
@@ -10,14 +10,22 @@ def get_indicators(
|
|||||||
look_back_days: Annotated[int, "how many days to look back"] = 30,
|
look_back_days: Annotated[int, "how many days to look back"] = 30,
|
||||||
) -> str:
|
) -> str:
|
||||||
"""
|
"""
|
||||||
Retrieve technical indicators for a given ticker symbol.
|
Retrieve a single technical indicator for a given ticker symbol.
|
||||||
Uses the configured technical_indicators vendor.
|
Uses the configured technical_indicators vendor.
|
||||||
Args:
|
Args:
|
||||||
symbol (str): Ticker symbol of the company, e.g. AAPL, TSM
|
symbol (str): Ticker symbol of the company, e.g. AAPL, TSM
|
||||||
indicator (str): Technical indicator to get the analysis and report of
|
indicator (str): A single technical indicator name, e.g. 'rsi', 'macd'. Call this tool once per indicator.
|
||||||
curr_date (str): The current trading date you are trading on, YYYY-mm-dd
|
curr_date (str): The current trading date you are trading on, YYYY-mm-dd
|
||||||
look_back_days (int): How many days to look back, default is 30
|
look_back_days (int): How many days to look back, default is 30
|
||||||
Returns:
|
Returns:
|
||||||
str: A formatted dataframe containing the technical indicators for the specified ticker symbol and indicator.
|
str: A formatted dataframe containing the technical indicators for the specified ticker symbol and indicator.
|
||||||
"""
|
"""
|
||||||
return route_to_vendor("get_indicators", symbol, indicator, curr_date, look_back_days)
|
# LLMs sometimes pass multiple indicators as a comma-separated string;
|
||||||
|
# split and process each individually.
|
||||||
|
indicators = [i.strip() for i in indicator.split(",") if i.strip()]
|
||||||
|
if len(indicators) > 1:
|
||||||
|
results = []
|
||||||
|
for ind in indicators:
|
||||||
|
results.append(route_to_vendor("get_indicators", symbol, ind, curr_date, look_back_days))
|
||||||
|
return "\n\n".join(results)
|
||||||
|
return route_to_vendor("get_indicators", symbol, indicator.strip(), curr_date, look_back_days)
|
||||||
@@ -6,6 +6,19 @@ import os
|
|||||||
from .config import get_config
|
from .config import get_config
|
||||||
|
|
||||||
|
|
||||||
|
def _clean_dataframe(data: pd.DataFrame) -> pd.DataFrame:
|
||||||
|
"""Normalize a stock DataFrame for stockstats: parse dates, drop invalid rows, fill price gaps."""
|
||||||
|
data["Date"] = pd.to_datetime(data["Date"], errors="coerce")
|
||||||
|
data = data.dropna(subset=["Date"])
|
||||||
|
|
||||||
|
price_cols = [c for c in ["Open", "High", "Low", "Close", "Volume"] if c in data.columns]
|
||||||
|
data[price_cols] = data[price_cols].apply(pd.to_numeric, errors="coerce")
|
||||||
|
data = data.dropna(subset=["Close"])
|
||||||
|
data[price_cols] = data[price_cols].ffill().bfill()
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
class StockstatsUtils:
|
class StockstatsUtils:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_stock_stats(
|
def get_stock_stats(
|
||||||
@@ -36,8 +49,7 @@ class StockstatsUtils:
|
|||||||
)
|
)
|
||||||
|
|
||||||
if os.path.exists(data_file):
|
if os.path.exists(data_file):
|
||||||
data = pd.read_csv(data_file)
|
data = pd.read_csv(data_file, on_bad_lines="skip")
|
||||||
data["Date"] = pd.to_datetime(data["Date"])
|
|
||||||
else:
|
else:
|
||||||
data = yf.download(
|
data = yf.download(
|
||||||
symbol,
|
symbol,
|
||||||
@@ -50,6 +62,7 @@ class StockstatsUtils:
|
|||||||
data = data.reset_index()
|
data = data.reset_index()
|
||||||
data.to_csv(data_file, index=False)
|
data.to_csv(data_file, index=False)
|
||||||
|
|
||||||
|
data = _clean_dataframe(data)
|
||||||
df = wrap(data)
|
df = wrap(data)
|
||||||
df["Date"] = df["Date"].dt.strftime("%Y-%m-%d")
|
df["Date"] = df["Date"].dt.strftime("%Y-%m-%d")
|
||||||
curr_date_str = curr_date_dt.strftime("%Y-%m-%d")
|
curr_date_str = curr_date_dt.strftime("%Y-%m-%d")
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ from datetime import datetime
|
|||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
import yfinance as yf
|
import yfinance as yf
|
||||||
import os
|
import os
|
||||||
from .stockstats_utils import StockstatsUtils
|
from .stockstats_utils import StockstatsUtils, _clean_dataframe
|
||||||
|
|
||||||
def get_YFin_data_online(
|
def get_YFin_data_online(
|
||||||
symbol: Annotated[str, "ticker symbol of the company"],
|
symbol: Annotated[str, "ticker symbol of the company"],
|
||||||
@@ -209,31 +209,30 @@ def _get_stock_stats_bulk(
|
|||||||
os.path.join(
|
os.path.join(
|
||||||
config.get("data_cache_dir", "data"),
|
config.get("data_cache_dir", "data"),
|
||||||
f"{symbol}-YFin-data-2015-01-01-2025-03-25.csv",
|
f"{symbol}-YFin-data-2015-01-01-2025-03-25.csv",
|
||||||
)
|
),
|
||||||
|
on_bad_lines="skip",
|
||||||
)
|
)
|
||||||
df = wrap(data)
|
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
raise Exception("Stockstats fail: Yahoo Finance data not fetched yet!")
|
raise Exception("Stockstats fail: Yahoo Finance data not fetched yet!")
|
||||||
else:
|
else:
|
||||||
# Online data fetching with caching
|
# Online data fetching with caching
|
||||||
today_date = pd.Timestamp.today()
|
today_date = pd.Timestamp.today()
|
||||||
curr_date_dt = pd.to_datetime(curr_date)
|
curr_date_dt = pd.to_datetime(curr_date)
|
||||||
|
|
||||||
end_date = today_date
|
end_date = today_date
|
||||||
start_date = today_date - pd.DateOffset(years=15)
|
start_date = today_date - pd.DateOffset(years=15)
|
||||||
start_date_str = start_date.strftime("%Y-%m-%d")
|
start_date_str = start_date.strftime("%Y-%m-%d")
|
||||||
end_date_str = end_date.strftime("%Y-%m-%d")
|
end_date_str = end_date.strftime("%Y-%m-%d")
|
||||||
|
|
||||||
os.makedirs(config["data_cache_dir"], exist_ok=True)
|
os.makedirs(config["data_cache_dir"], exist_ok=True)
|
||||||
|
|
||||||
data_file = os.path.join(
|
data_file = os.path.join(
|
||||||
config["data_cache_dir"],
|
config["data_cache_dir"],
|
||||||
f"{symbol}-YFin-data-{start_date_str}-{end_date_str}.csv",
|
f"{symbol}-YFin-data-{start_date_str}-{end_date_str}.csv",
|
||||||
)
|
)
|
||||||
|
|
||||||
if os.path.exists(data_file):
|
if os.path.exists(data_file):
|
||||||
data = pd.read_csv(data_file)
|
data = pd.read_csv(data_file, on_bad_lines="skip")
|
||||||
data["Date"] = pd.to_datetime(data["Date"])
|
|
||||||
else:
|
else:
|
||||||
data = yf.download(
|
data = yf.download(
|
||||||
symbol,
|
symbol,
|
||||||
@@ -245,9 +244,10 @@ def _get_stock_stats_bulk(
|
|||||||
)
|
)
|
||||||
data = data.reset_index()
|
data = data.reset_index()
|
||||||
data.to_csv(data_file, index=False)
|
data.to_csv(data_file, index=False)
|
||||||
|
|
||||||
df = wrap(data)
|
data = _clean_dataframe(data)
|
||||||
df["Date"] = df["Date"].dt.strftime("%Y-%m-%d")
|
df = wrap(data)
|
||||||
|
df["Date"] = df["Date"].dt.strftime("%Y-%m-%d")
|
||||||
|
|
||||||
# Calculate the indicator for all rows at once
|
# Calculate the indicator for all rows at once
|
||||||
df[indicator] # This triggers stockstats to calculate the indicator
|
df[indicator] # This triggers stockstats to calculate the indicator
|
||||||
|
|||||||
@@ -24,14 +24,26 @@ class Propagator:
|
|||||||
"company_of_interest": company_name,
|
"company_of_interest": company_name,
|
||||||
"trade_date": str(trade_date),
|
"trade_date": str(trade_date),
|
||||||
"investment_debate_state": InvestDebateState(
|
"investment_debate_state": InvestDebateState(
|
||||||
{"history": "", "current_response": "", "count": 0}
|
{
|
||||||
|
"bull_history": "",
|
||||||
|
"bear_history": "",
|
||||||
|
"history": "",
|
||||||
|
"current_response": "",
|
||||||
|
"judge_decision": "",
|
||||||
|
"count": 0,
|
||||||
|
}
|
||||||
),
|
),
|
||||||
"risk_debate_state": RiskDebateState(
|
"risk_debate_state": RiskDebateState(
|
||||||
{
|
{
|
||||||
|
"aggressive_history": "",
|
||||||
|
"conservative_history": "",
|
||||||
|
"neutral_history": "",
|
||||||
"history": "",
|
"history": "",
|
||||||
|
"latest_speaker": "",
|
||||||
"current_aggressive_response": "",
|
"current_aggressive_response": "",
|
||||||
"current_conservative_response": "",
|
"current_conservative_response": "",
|
||||||
"current_neutral_response": "",
|
"current_neutral_response": "",
|
||||||
|
"judge_decision": "",
|
||||||
"count": 0,
|
"count": 0,
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -105,7 +105,10 @@ class TradingAgentsGraph:
|
|||||||
self.tool_nodes = self._create_tool_nodes()
|
self.tool_nodes = self._create_tool_nodes()
|
||||||
|
|
||||||
# Initialize components
|
# Initialize components
|
||||||
self.conditional_logic = ConditionalLogic()
|
self.conditional_logic = ConditionalLogic(
|
||||||
|
max_debate_rounds=self.config["max_debate_rounds"],
|
||||||
|
max_risk_discuss_rounds=self.config["max_risk_discuss_rounds"],
|
||||||
|
)
|
||||||
self.graph_setup = GraphSetup(
|
self.graph_setup = GraphSetup(
|
||||||
self.quick_thinking_llm,
|
self.quick_thinking_llm,
|
||||||
self.deep_thinking_llm,
|
self.deep_thinking_llm,
|
||||||
@@ -257,6 +260,7 @@ class TradingAgentsGraph:
|
|||||||
with open(
|
with open(
|
||||||
f"eval_results/{self.ticker}/TradingAgentsStrategy_logs/full_states_log_{trade_date}.json",
|
f"eval_results/{self.ticker}/TradingAgentsStrategy_logs/full_states_log_{trade_date}.json",
|
||||||
"w",
|
"w",
|
||||||
|
encoding="utf-8",
|
||||||
) as f:
|
) as f:
|
||||||
json.dump(self.log_states_dict, f, indent=4)
|
json.dump(self.log_states_dict, f, indent=4)
|
||||||
|
|
||||||
|
|||||||
@@ -8,25 +8,23 @@ from .validators import validate_model
|
|||||||
|
|
||||||
|
|
||||||
class UnifiedChatOpenAI(ChatOpenAI):
|
class UnifiedChatOpenAI(ChatOpenAI):
|
||||||
"""ChatOpenAI subclass that strips incompatible params for certain models."""
|
"""ChatOpenAI subclass that strips temperature/top_p for GPT-5 family models.
|
||||||
|
|
||||||
|
GPT-5 family models use reasoning natively. temperature/top_p are only
|
||||||
|
accepted when reasoning.effort is 'none'; with any other effort level
|
||||||
|
(or for older GPT-5/GPT-5-mini/GPT-5-nano which always reason) the API
|
||||||
|
rejects these params. Langchain defaults temperature=0.7, so we must
|
||||||
|
strip it to avoid errors.
|
||||||
|
|
||||||
|
Non-GPT-5 models (GPT-4.1, xAI, Ollama, etc.) are unaffected.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
model = kwargs.get("model", "")
|
if "gpt-5" in kwargs.get("model", "").lower():
|
||||||
if self._is_reasoning_model(model):
|
|
||||||
kwargs.pop("temperature", None)
|
kwargs.pop("temperature", None)
|
||||||
kwargs.pop("top_p", None)
|
kwargs.pop("top_p", None)
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _is_reasoning_model(model: str) -> bool:
|
|
||||||
"""Check if model is a reasoning model that doesn't support temperature."""
|
|
||||||
model_lower = model.lower()
|
|
||||||
return (
|
|
||||||
model_lower.startswith("o1")
|
|
||||||
or model_lower.startswith("o3")
|
|
||||||
or "gpt-5" in model_lower
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class OpenAIClient(BaseLLMClient):
|
class OpenAIClient(BaseLLMClient):
|
||||||
"""Client for OpenAI, Ollama, OpenRouter, and xAI providers."""
|
"""Client for OpenAI, Ollama, OpenRouter, and xAI providers."""
|
||||||
|
|||||||
@@ -6,59 +6,44 @@ Let LLM providers use their own defaults for unspecified params.
|
|||||||
|
|
||||||
VALID_MODELS = {
|
VALID_MODELS = {
|
||||||
"openai": [
|
"openai": [
|
||||||
# GPT-5 series (2025)
|
# GPT-5 series
|
||||||
|
"gpt-5.4-pro",
|
||||||
|
"gpt-5.4",
|
||||||
"gpt-5.2",
|
"gpt-5.2",
|
||||||
"gpt-5.1",
|
"gpt-5.1",
|
||||||
"gpt-5",
|
"gpt-5",
|
||||||
"gpt-5-mini",
|
"gpt-5-mini",
|
||||||
"gpt-5-nano",
|
"gpt-5-nano",
|
||||||
# GPT-4.1 series (2025)
|
# GPT-4.1 series
|
||||||
"gpt-4.1",
|
"gpt-4.1",
|
||||||
"gpt-4.1-mini",
|
"gpt-4.1-mini",
|
||||||
"gpt-4.1-nano",
|
"gpt-4.1-nano",
|
||||||
# o-series reasoning models
|
|
||||||
"o4-mini",
|
|
||||||
"o3",
|
|
||||||
"o3-mini",
|
|
||||||
"o1",
|
|
||||||
"o1-preview",
|
|
||||||
# GPT-4o series (legacy but still supported)
|
|
||||||
"gpt-4o",
|
|
||||||
"gpt-4o-mini",
|
|
||||||
],
|
],
|
||||||
"anthropic": [
|
"anthropic": [
|
||||||
# Claude 4.5 series (2025)
|
# Claude 4.6 series (latest)
|
||||||
|
"claude-opus-4-6",
|
||||||
|
"claude-sonnet-4-6",
|
||||||
|
# Claude 4.5 series
|
||||||
"claude-opus-4-5",
|
"claude-opus-4-5",
|
||||||
"claude-sonnet-4-5",
|
"claude-sonnet-4-5",
|
||||||
"claude-haiku-4-5",
|
"claude-haiku-4-5",
|
||||||
# Claude 4.x series
|
|
||||||
"claude-opus-4-1-20250805",
|
|
||||||
"claude-sonnet-4-20250514",
|
|
||||||
# Claude 3.7 series
|
|
||||||
"claude-3-7-sonnet-20250219",
|
|
||||||
# Claude 3.5 series (legacy)
|
|
||||||
"claude-3-5-haiku-20241022",
|
|
||||||
"claude-3-5-sonnet-20241022",
|
|
||||||
],
|
],
|
||||||
"google": [
|
"google": [
|
||||||
|
# Gemini 3.1 series (preview)
|
||||||
|
"gemini-3.1-pro-preview",
|
||||||
|
"gemini-3.1-flash-lite-preview",
|
||||||
# Gemini 3 series (preview)
|
# Gemini 3 series (preview)
|
||||||
"gemini-3-pro-preview",
|
|
||||||
"gemini-3-flash-preview",
|
"gemini-3-flash-preview",
|
||||||
# Gemini 2.5 series
|
# Gemini 2.5 series
|
||||||
"gemini-2.5-pro",
|
"gemini-2.5-pro",
|
||||||
"gemini-2.5-flash",
|
"gemini-2.5-flash",
|
||||||
"gemini-2.5-flash-lite",
|
"gemini-2.5-flash-lite",
|
||||||
# Gemini 2.0 series
|
|
||||||
"gemini-2.0-flash",
|
|
||||||
"gemini-2.0-flash-lite",
|
|
||||||
],
|
],
|
||||||
"xai": [
|
"xai": [
|
||||||
# Grok 4.1 series
|
# Grok 4.1 series
|
||||||
"grok-4-1-fast",
|
|
||||||
"grok-4-1-fast-reasoning",
|
"grok-4-1-fast-reasoning",
|
||||||
"grok-4-1-fast-non-reasoning",
|
"grok-4-1-fast-non-reasoning",
|
||||||
# Grok 4 series
|
# Grok 4 series
|
||||||
"grok-4",
|
|
||||||
"grok-4-0709",
|
"grok-4-0709",
|
||||||
"grok-4-fast-reasoning",
|
"grok-4-fast-reasoning",
|
||||||
"grok-4-fast-non-reasoning",
|
"grok-4-fast-non-reasoning",
|
||||||
|
|||||||
42
uv.lock
generated
42
uv.lock
generated
@@ -1134,7 +1134,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "langchain-core"
|
name = "langchain-core"
|
||||||
version = "0.3.65"
|
version = "0.3.83"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "jsonpatch" },
|
{ name = "jsonpatch" },
|
||||||
@@ -1144,10 +1144,11 @@ dependencies = [
|
|||||||
{ name = "pyyaml" },
|
{ name = "pyyaml" },
|
||||||
{ name = "tenacity" },
|
{ name = "tenacity" },
|
||||||
{ name = "typing-extensions" },
|
{ name = "typing-extensions" },
|
||||||
|
{ name = "uuid-utils" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/04/8a/d08c83195d1ef26c42728412ab92ab08211893906b283abce65775e21327/langchain_core-0.3.65.tar.gz", hash = "sha256:54b5e0c8d9bb405415c3211da508ef9cfe0acbe5b490d1b4a15664408ee82d9b", size = 558557, upload-time = "2025-06-10T20:08:28.94Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/21/a4/24f2d787bfcf56e5990924cacefe6f6e7971a3629f97c8162fc7a2a3d851/langchain_core-0.3.83.tar.gz", hash = "sha256:a0a4c7b6ea1c446d3b432116f405dc2afa1fe7891c44140d3d5acca221909415", size = 597965, upload-time = "2026-01-13T01:19:23.854Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/54/f0/31db18b7b8213266aed926ce89b5bdd84ccde7ee2edf4cab14e3dd2bfcf1/langchain_core-0.3.65-py3-none-any.whl", hash = "sha256:80e8faf6e9f331f8ef728f3fe793549f1d3fb244fcf9e1bdcecab6a6f4669394", size = 438052, upload-time = "2025-06-10T20:08:27.393Z" },
|
{ url = "https://files.pythonhosted.org/packages/5a/db/d71b80d3bd6193812485acea4001cdf86cf95a44bbf942f7a240120ff762/langchain_core-0.3.83-py3-none-any.whl", hash = "sha256:8c92506f8b53fc1958b1c07447f58c5783eb8833dd3cb6dc75607c80891ab1ae", size = 458890, upload-time = "2026-01-13T01:19:21.748Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3498,12 +3499,13 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tradingagents"
|
name = "tradingagents"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
source = { virtual = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "backtrader" },
|
{ name = "backtrader" },
|
||||||
{ name = "chainlit" },
|
{ name = "chainlit" },
|
||||||
{ name = "langchain-anthropic" },
|
{ name = "langchain-anthropic" },
|
||||||
|
{ name = "langchain-core" },
|
||||||
{ name = "langchain-experimental" },
|
{ name = "langchain-experimental" },
|
||||||
{ name = "langchain-google-genai" },
|
{ name = "langchain-google-genai" },
|
||||||
{ name = "langchain-openai" },
|
{ name = "langchain-openai" },
|
||||||
@@ -3529,6 +3531,7 @@ requires-dist = [
|
|||||||
{ name = "backtrader", specifier = ">=1.9.78.123" },
|
{ name = "backtrader", specifier = ">=1.9.78.123" },
|
||||||
{ name = "chainlit", specifier = ">=2.5.5" },
|
{ name = "chainlit", specifier = ">=2.5.5" },
|
||||||
{ name = "langchain-anthropic", specifier = ">=0.3.15" },
|
{ name = "langchain-anthropic", specifier = ">=0.3.15" },
|
||||||
|
{ name = "langchain-core", specifier = ">=0.3.81" },
|
||||||
{ name = "langchain-experimental", specifier = ">=0.3.4" },
|
{ name = "langchain-experimental", specifier = ">=0.3.4" },
|
||||||
{ name = "langchain-google-genai", specifier = ">=2.1.5" },
|
{ name = "langchain-google-genai", specifier = ">=2.1.5" },
|
||||||
{ name = "langchain-openai", specifier = ">=0.3.23" },
|
{ name = "langchain-openai", specifier = ">=0.3.23" },
|
||||||
@@ -3631,6 +3634,35 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/6b/11/cc635220681e93a0183390e26485430ca2c7b5f9d33b15c74c2861cb8091/urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813", size = 128680, upload-time = "2025-04-10T15:23:37.377Z" },
|
{ url = "https://files.pythonhosted.org/packages/6b/11/cc635220681e93a0183390e26485430ca2c7b5f9d33b15c74c2861cb8091/urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813", size = 128680, upload-time = "2025-04-10T15:23:37.377Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uuid-utils"
|
||||||
|
version = "0.14.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/57/7c/3a926e847516e67bc6838634f2e54e24381105b4e80f9338dc35cca0086b/uuid_utils-0.14.0.tar.gz", hash = "sha256:fc5bac21e9933ea6c590433c11aa54aaca599f690c08069e364eb13a12f670b4", size = 22072, upload-time = "2026-01-20T20:37:15.729Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a7/42/42d003f4a99ddc901eef2fd41acb3694163835e037fb6dde79ad68a72342/uuid_utils-0.14.0-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:f6695c0bed8b18a904321e115afe73b34444bc8451d0ce3244a1ec3b84deb0e5", size = 601786, upload-time = "2026-01-20T20:37:09.843Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/96/e6/775dfb91f74b18f7207e3201eb31ee666d286579990dc69dd50db2d92813/uuid_utils-0.14.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:4f0a730bbf2d8bb2c11b93e1005e91769f2f533fa1125ed1f00fd15b6fcc732b", size = 303943, upload-time = "2026-01-20T20:37:18.767Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/17/82/ea5f5e85560b08a1f30cdc65f75e76494dc7aba9773f679e7eaa27370229/uuid_utils-0.14.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40ce3fd1a4fdedae618fc3edc8faf91897012469169d600133470f49fd699ed3", size = 340467, upload-time = "2026-01-20T20:37:11.794Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ca/33/54b06415767f4569882e99b6470c6c8eeb97422686a6d432464f9967fd91/uuid_utils-0.14.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:09ae4a98416a440e78f7d9543d11b11cae4bab538b7ed94ec5da5221481748f2", size = 346333, upload-time = "2026-01-20T20:37:12.818Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cb/10/a6bce636b8f95e65dc84bf4a58ce8205b8e0a2a300a38cdbc83a3f763d27/uuid_utils-0.14.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:971e8c26b90d8ae727e7f2ac3ee23e265971d448b3672882f2eb44828b2b8c3e", size = 470859, upload-time = "2026-01-20T20:37:01.512Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8a/27/84121c51ea72f013f0e03d0886bcdfa96b31c9b83c98300a7bd5cc4fa191/uuid_utils-0.14.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5cde1fa82804a8f9d2907b7aec2009d440062c63f04abbdb825fce717a5e860", size = 341988, upload-time = "2026-01-20T20:37:22.881Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/90/a4/01c1c7af5e6a44f20b40183e8dac37d6ed83e7dc9e8df85370a15959b804/uuid_utils-0.14.0-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c7343862a2359e0bd48a7f3dfb5105877a1728677818bb694d9f40703264a2db", size = 365784, upload-time = "2026-01-20T20:37:10.808Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/04/f0/65ee43ec617b8b6b1bf2a5aecd56a069a08cca3d9340c1de86024331bde3/uuid_utils-0.14.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c51e4818fdb08ccec12dc7083a01f49507b4608770a0ab22368001685d59381b", size = 523750, upload-time = "2026-01-20T20:37:06.152Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/95/d3/6bf503e3f135a5dfe705a65e6f89f19bccd55ac3fb16cb5d3ec5ba5388b8/uuid_utils-0.14.0-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:181bbcccb6f93d80a8504b5bd47b311a1c31395139596edbc47b154b0685b533", size = 615818, upload-time = "2026-01-20T20:37:21.816Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/df/6c/99937dd78d07f73bba831c8dc9469dfe4696539eba2fc269ae1b92752f9e/uuid_utils-0.14.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:5c8ae96101c3524ba8dbf762b6f05e9e9d896544786c503a727c5bf5cb9af1a7", size = 580831, upload-time = "2026-01-20T20:37:19.691Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/44/fa/bbc9e2c25abd09a293b9b097a0d8fc16acd6a92854f0ec080f1ea7ad8bb3/uuid_utils-0.14.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:00ac3c6edfdaff7e1eed041f4800ae09a3361287be780d7610a90fdcde9befdc", size = 546333, upload-time = "2026-01-20T20:37:03.117Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e7/9b/e5e99b324b1b5f0c62882230455786df0bc66f67eff3b452447e703f45d2/uuid_utils-0.14.0-cp39-abi3-win32.whl", hash = "sha256:ec2fd80adf8e0e6589d40699e6f6df94c93edcc16dd999be0438dd007c77b151", size = 177319, upload-time = "2026-01-20T20:37:04.208Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d3/28/2c7d417ea483b6ff7820c948678fdf2ac98899dc7e43bb15852faa95acaf/uuid_utils-0.14.0-cp39-abi3-win_amd64.whl", hash = "sha256:efe881eb43a5504fad922644cb93d725fd8a6a6d949bd5a4b4b7d1a1587c7fd1", size = 182566, upload-time = "2026-01-20T20:37:16.868Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b8/86/49e4bdda28e962fbd7266684171ee29b3d92019116971d58783e51770745/uuid_utils-0.14.0-cp39-abi3-win_arm64.whl", hash = "sha256:32b372b8fd4ebd44d3a219e093fe981af4afdeda2994ee7db208ab065cfcd080", size = 182809, upload-time = "2026-01-20T20:37:05.139Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f1/03/1f1146e32e94d1f260dfabc81e1649102083303fb4ad549775c943425d9a/uuid_utils-0.14.0-pp311-pypy311_pp73-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:762e8d67992ac4d2454e24a141a1c82142b5bde10409818c62adbe9924ebc86d", size = 587430, upload-time = "2026-01-20T20:37:24.998Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/87/ba/d5a7469362594d885fd9219fe9e851efbe65101d3ef1ef25ea321d7ce841/uuid_utils-0.14.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:40be5bf0b13aa849d9062abc86c198be6a25ff35316ce0b89fc25f3bac6d525e", size = 298106, upload-time = "2026-01-20T20:37:23.896Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8a/11/3dafb2a5502586f59fd49e93f5802cd5face82921b3a0f3abb5f357cb879/uuid_utils-0.14.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:191a90a6f3940d1b7322b6e6cceff4dd533c943659e0a15f788674407856a515", size = 333423, upload-time = "2026-01-20T20:37:17.828Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7c/f2/c8987663f0cdcf4d717a36d85b5db2a5589df0a4e129aa10f16f4380ef48/uuid_utils-0.14.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4aa4525f4ad82f9d9c842f9a3703f1539c1808affbaec07bb1b842f6b8b96aa5", size = 338659, upload-time = "2026-01-20T20:37:14.286Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d1/c8/929d81665d83f0b2ffaecb8e66c3091a50f62c7cb5b65e678bd75a96684e/uuid_utils-0.14.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cdbd82ff20147461caefc375551595ecf77ebb384e46267f128aca45a0f2cdfc", size = 467029, upload-time = "2026-01-20T20:37:08.277Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8e/a0/27d7daa1bfed7163f4ccaf52d7d2f4ad7bb1002a85b45077938b91ee584f/uuid_utils-0.14.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eff57e8a5d540006ce73cf0841a643d445afe78ba12e75ac53a95ca2924a56be", size = 333298, upload-time = "2026-01-20T20:37:07.271Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/63/d4/acad86ce012b42ce18a12f31ee2aa3cbeeb98664f865f05f68c882945913/uuid_utils-0.14.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3fd9112ca96978361201e669729784f26c71fecc9c13a7f8a07162c31bd4d1e2", size = 359217, upload-time = "2026-01-20T20:36:59.687Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uvicorn"
|
name = "uvicorn"
|
||||||
version = "0.34.3"
|
version = "0.34.3"
|
||||||
|
|||||||
Reference in New Issue
Block a user