Merge branch 'main' into profile-analyst
This commit is contained in:
commit
3ba1d5fee9
17
.env.example
17
.env.example
|
|
@ -8,3 +8,20 @@ TAAPI_API_KEY=taapi_api_key_placeholder
|
|||
BYBIT_BASE_URL=https://api-demo.bybit.com
|
||||
BYBIT_API_KEY=bybit_api_key_placeholder
|
||||
BYBIT_API_SECRET=bybit_api_secret_placeholder
|
||||
COIN_GECKO_API_BASE_URL=https://api.coingecko.com/api/v3
|
||||
|
||||
# Model settings
|
||||
LLM_PROVIDER=openai
|
||||
BACKEND_URL=https://api.openai.com/v1
|
||||
DEEP_THINK_LLM=gpt-4o-mini
|
||||
QUICK_THINK_LLM=gpt-4o-mini
|
||||
|
||||
# App settings
|
||||
APP_HOST=localhost
|
||||
APP_PORT=8000
|
||||
|
||||
# Redis
|
||||
REDIS_HOST=localhost
|
||||
REDIS_PORT=6379
|
||||
REDIS_PASSWORD=default-password
|
||||
REDIS_DB=0
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
3.12.7
|
||||
24
README.md
24
README.md
|
|
@ -110,23 +110,25 @@ conda activate tradingagents
|
|||
pyenv
|
||||
pyenv local 3.12.7
|
||||
python -m venv .venv
|
||||
source./venv/bin/activate
|
||||
python --version
|
||||
pip install --upgrade pip
|
||||
pip install -r requirements.txt
|
||||
pip list
|
||||
|
||||
# daily use
|
||||
source .venv/bin/activate
|
||||
python --version
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install -r requirements.txt
|
||||
python -m pip list
|
||||
|
||||
deactivate
|
||||
|
||||
if error mini-racer
|
||||
source venv/bin/activate && pip install --no-deps -r requirements.txt #install without miniracer
|
||||
source .venv/bin/activate && pip install --no-deps -r requirements.txt #install without miniracer
|
||||
|
||||
Api
|
||||
python webapp.py
|
||||
```
|
||||
|
||||
Install dependencies:
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
### Connect to Redis (Local)
|
||||
```
|
||||
docker-compose up -d
|
||||
redis-cli -h localhost -p 6379 -a {REDIS_PASSWORD}
|
||||
```
|
||||
|
||||
### Required APIs
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
services:
|
||||
redis:
|
||||
image: redis:7.4.7
|
||||
container_name: ${REDIS_CONTAINER_NAME:-trading_agents_redis}
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "6379:6379"
|
||||
volumes:
|
||||
- redis-data:/data
|
||||
environment:
|
||||
REDIS_PASSWORD: ${REDIS_PASSWORD}
|
||||
command: >
|
||||
redis-server
|
||||
--appendonly yes
|
||||
--requirepass ${REDIS_PASSWORD}
|
||||
|
||||
volumes:
|
||||
redis-data:
|
||||
|
|
@ -28,6 +28,8 @@ dependencies = [
|
|||
"rich>=14.0.0",
|
||||
"setuptools>=80.9.0",
|
||||
"stockstats>=0.6.5",
|
||||
"fastapi>=0.115.0",
|
||||
"uvicorn[standard]>=0.32.0",
|
||||
"tqdm>=4.67.1",
|
||||
"tushare>=1.4.21",
|
||||
"typing-extensions>=4.14.0",
|
||||
|
|
|
|||
|
|
@ -26,4 +26,6 @@ langchain_anthropic
|
|||
langchain-google-genai
|
||||
binance-sdk-spot
|
||||
telethon
|
||||
pybit
|
||||
fastapi
|
||||
uvicorn[standard]
|
||||
redis[hiredis]
|
||||
|
|
|
|||
|
|
@ -1,15 +1,11 @@
|
|||
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
|
||||
import time
|
||||
import json
|
||||
from tradingagents.agents.utils.agent_utils import get_fundamentals, get_whitepaper, get_market_cap
|
||||
from tradingagents.dataflows.config import get_config
|
||||
|
||||
|
||||
def create_fundamentals_analyst(llm):
|
||||
def fundamentals_analyst_node(state):
|
||||
current_date = state["trade_date"]
|
||||
ticker = state["ticker_of_interest"]
|
||||
company_name = state["ticker_of_interest"]
|
||||
|
||||
tools = [
|
||||
get_fundamentals,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,5 @@
|
|||
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
|
||||
import time
|
||||
import json
|
||||
from tradingagents.agents.utils.agent_utils import get_news, get_global_news
|
||||
from tradingagents.dataflows.config import get_config
|
||||
|
||||
|
||||
def create_news_analyst(llm):
|
||||
def news_analyst_node(state):
|
||||
|
|
|
|||
|
|
@ -1,15 +1,11 @@
|
|||
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
|
||||
import time
|
||||
import json
|
||||
from tradingagents.agents.utils.agent_utils import get_news, get_fear_and_greed
|
||||
from tradingagents.dataflows.config import get_config
|
||||
|
||||
|
||||
def create_social_media_analyst(llm):
|
||||
def social_media_analyst_node(state):
|
||||
current_date = state["trade_date"]
|
||||
ticker = state["ticker_of_interest"]
|
||||
coin_name = state["ticker_of_interest"]
|
||||
|
||||
tools = [
|
||||
get_news,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
import time
|
||||
import json
|
||||
from tradingagents.agents.utils.memory import FinancialSituationMemory
|
||||
|
||||
|
||||
def create_research_manager(llm, memory):
|
||||
def create_research_manager(llm, memory: FinancialSituationMemory):
|
||||
def research_manager_node(state) -> dict:
|
||||
history = state["investment_debate_state"].get("history", "")
|
||||
market_research_report = state["market_report"]
|
||||
|
|
|
|||
|
|
@ -1,12 +1,8 @@
|
|||
import time
|
||||
import json
|
||||
from tradingagents.agents.utils.memory import FinancialSituationMemory
|
||||
|
||||
|
||||
def create_risk_manager(llm, memory):
|
||||
def create_risk_manager(llm, memory: FinancialSituationMemory):
|
||||
def risk_manager_node(state) -> dict:
|
||||
|
||||
company_name = state["company_of_interest"]
|
||||
|
||||
history = state["risk_debate_state"]["history"]
|
||||
risk_debate_state = state["risk_debate_state"]
|
||||
market_research_report = state["market_report"]
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
from langchain_core.messages import AIMessage
|
||||
import time
|
||||
import json
|
||||
from tradingagents.agents.utils.memory import FinancialSituationMemory
|
||||
|
||||
|
||||
def create_bear_researcher(llm, memory):
|
||||
def create_bear_researcher(llm, memory: FinancialSituationMemory):
|
||||
def bear_node(state) -> dict:
|
||||
investment_debate_state = state["investment_debate_state"]
|
||||
history = investment_debate_state.get("history", "")
|
||||
|
|
@ -38,7 +35,7 @@ Resources available:
|
|||
Market research report: {market_research_report}
|
||||
Social media sentiment report: {sentiment_report}
|
||||
Latest world affairs news: {news_report}
|
||||
Company fundamentals report: {fundamentals_report}
|
||||
Coin fundamentals report: {fundamentals_report}
|
||||
Profile analysis report: {profile_report}
|
||||
Conversation history of the debate: {history}
|
||||
Last bull argument: {current_response}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
from langchain_core.messages import AIMessage
|
||||
import time
|
||||
import json
|
||||
from tradingagents.agents.utils.memory import FinancialSituationMemory
|
||||
|
||||
|
||||
def create_bull_researcher(llm, memory):
|
||||
def create_bull_researcher(llm, memory: FinancialSituationMemory):
|
||||
def bull_node(state) -> dict:
|
||||
investment_debate_state = state["investment_debate_state"]
|
||||
history = investment_debate_state.get("history", "")
|
||||
|
|
|
|||
|
|
@ -1,7 +1,3 @@
|
|||
import time
|
||||
import json
|
||||
|
||||
|
||||
def create_risky_debator(llm):
|
||||
def risky_node(state) -> dict:
|
||||
risk_debate_state = state["risk_debate_state"]
|
||||
|
|
|
|||
|
|
@ -1,8 +1,3 @@
|
|||
from langchain_core.messages import AIMessage
|
||||
import time
|
||||
import json
|
||||
|
||||
|
||||
def create_safe_debator(llm):
|
||||
def safe_node(state) -> dict:
|
||||
risk_debate_state = state["risk_debate_state"]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,3 @@
|
|||
import time
|
||||
import json
|
||||
|
||||
|
||||
def create_neutral_debator(llm):
|
||||
def neutral_node(state) -> dict:
|
||||
risk_debate_state = state["risk_debate_state"]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,4 @@
|
|||
import functools
|
||||
import time
|
||||
import json
|
||||
|
||||
|
||||
def create_trader(llm, memory):
|
||||
def trader_node(state, name):
|
||||
|
|
@ -40,7 +37,9 @@ def create_trader(llm, memory):
|
|||
messages = [
|
||||
{
|
||||
"role": "system",
|
||||
"content": f"""You are a crypto trading agent analyzing cryptocurrency market data for a specific trading pair (e.g., BTC/USDT). Based on your analysis, provide a specific recommendation to BUY, SELL, or HOLD the base asset relative to the quote asset for the pair {pair_context}. End with a firm decision and always conclude your response with 'FINAL TRANSACTION PROPOSAL: **BUY/HOLD/SELL**' to confirm your recommendation. Do not forget to utilize lessons from past decisions to learn from your mistakes. Here is some reflections from similar situations you traded in and the lessons learned: {past_memory_str}""",
|
||||
"content": f"""You are a crypto trading agent analyzing cryptocurrency market data for a specific trading pair (e.g., BTC/USDT). Based on your analysis, provide a specific recommendation to BUY, SELL, or HOLD the base asset relative to the quote asset for the pair {pair_context}, along with the quantity for BUY and SELL \
|
||||
End with a firm decision and always conclude your response with 'FINAL TRANSACTION PROPOSAL: **BUY/HOLD/SELL** **QUANTITY**' to confirm your recommendation. \
|
||||
Do not forget to utilize lessons from past decisions to learn from your mistakes. Here is some reflections from similar situations you traded in and the lessons learned: {past_memory_str}""",
|
||||
},
|
||||
context,
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,10 +1,7 @@
|
|||
from typing import Annotated, Sequence
|
||||
from datetime import date, timedelta, datetime
|
||||
from typing_extensions import TypedDict, Optional
|
||||
from langchain_openai import ChatOpenAI
|
||||
from typing import Annotated
|
||||
from typing_extensions import TypedDict
|
||||
from tradingagents.agents import *
|
||||
from langgraph.prebuilt import ToolNode
|
||||
from langgraph.graph import END, StateGraph, START, MessagesState
|
||||
from langgraph.graph import MessagesState
|
||||
|
||||
|
||||
# Researcher team state
|
||||
|
|
@ -48,7 +45,6 @@ class RiskDebateState(TypedDict):
|
|||
|
||||
|
||||
class AgentState(MessagesState):
|
||||
company_of_interest: Annotated[str, "Company that we are interested in trading"]
|
||||
ticker_of_interest: Annotated[str, "Ticker that we are interested in trading"] # e.g BTC/USDT
|
||||
trade_date: Annotated[str, "What date we are trading at"]
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ class FinancialSituationMemory:
|
|||
self.embedding = "text-embedding-3-small"
|
||||
self.client = OpenAI(base_url=config["backend_url"])
|
||||
self.chroma_client = chromadb.Client(Settings(allow_reset=True))
|
||||
self.situation_collection = self.chroma_client.create_collection(name=name)
|
||||
self.situation_collection = self.chroma_client.get_or_create_collection(name=name)
|
||||
|
||||
def get_embedding(self, text):
|
||||
"""Get OpenAI embedding for a text"""
|
||||
|
|
|
|||
|
|
@ -1,20 +1,33 @@
|
|||
from binance_common.configuration import ConfigurationRestAPI
|
||||
from binance_common.constants import SPOT_REST_API_PROD_URL
|
||||
from binance_sdk_spot.spot import Spot
|
||||
import os
|
||||
from datetime import datetime
|
||||
import csv
|
||||
import io
|
||||
from tradingagents.dataflows.config import get_config
|
||||
|
||||
def get_api_key() -> str:
|
||||
"""Retrieve the API key for Binance from environment variables."""
|
||||
api_key = os.getenv("BINANCE_API_KEY")
|
||||
if not api_key:
|
||||
raise ValueError("BINANCE_API_KEY environment variable is not set.")
|
||||
return api_key
|
||||
_client = None
|
||||
|
||||
configuration = ConfigurationRestAPI(api_key=get_api_key(), base_path=SPOT_REST_API_PROD_URL)
|
||||
client = Spot(config_rest_api=configuration)
|
||||
def get_binance_client():
|
||||
"""Get or create Binance client with lazy initialization."""
|
||||
global _client
|
||||
if _client is None:
|
||||
try:
|
||||
config = get_config()
|
||||
api_key = config["external"].get("BINANCE_API_KEY", "")
|
||||
if not api_key:
|
||||
raise ValueError("BINANCE_API_KEY not found in configuration")
|
||||
|
||||
configuration = ConfigurationRestAPI(
|
||||
api_key=api_key,
|
||||
base_path=SPOT_REST_API_PROD_URL
|
||||
)
|
||||
_client = Spot(config_rest_api=configuration)
|
||||
except Exception as e:
|
||||
print(f"ERROR: Failed to initialize Binance client: {e}")
|
||||
raise
|
||||
|
||||
return _client
|
||||
|
||||
def get_market_data(symbol: str, start_date: str, end_date: str):
|
||||
"""Fetch market data for a given symbol from Binance. Get OHLCV data. interval is 1 day.
|
||||
|
|
@ -36,6 +49,7 @@ def get_market_data(symbol: str, start_date: str, end_date: str):
|
|||
|
||||
# print(f"DEBUG: Fetching data for {formatted_symbol} from {start_date} to {end_date}")
|
||||
try:
|
||||
client = get_binance_client()
|
||||
response = client.rest_api.klines(
|
||||
symbol=formatted_symbol,
|
||||
start_time=start_epoch,
|
||||
|
|
@ -80,6 +94,8 @@ def get_market_data(symbol: str, start_date: str, end_date: str):
|
|||
csv_string = output.getvalue()
|
||||
output.close()
|
||||
|
||||
title = f"# Market Data for {symbol} from {start_date} to {end_date}\n\n"
|
||||
csv_string = title + csv_string
|
||||
return csv_string
|
||||
|
||||
except Exception as e:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import requests
|
||||
from .alpha_vantage_common import API_BASE_URL
|
||||
from tradingagents.dataflows.config import get_config
|
||||
|
||||
def get_market_cap() -> str:
|
||||
"""
|
||||
|
|
@ -8,8 +9,11 @@ def get_market_cap() -> str:
|
|||
Returns:
|
||||
str: Market capitalization percentage data for cryptocurrencies
|
||||
"""
|
||||
endpoint = f"https://api.coingecko.com/api/v3/global"
|
||||
config = get_config()
|
||||
api_base_url = config["external"].get("COIN_GECKO_API_BASE_URL", "https://api.coingecko.com/api/v3")
|
||||
endpoint = f"{api_base_url}/global"
|
||||
response = requests.get(endpoint)
|
||||
print(f"DEBUG: CoinGecko API response status code: {response.status_code}")
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
market_cap_pct = data.get("data", {}).get("market_cap_percentage", {})
|
||||
|
|
@ -18,4 +22,4 @@ def get_market_cap() -> str:
|
|||
for coin, percentage in market_cap_pct.items():
|
||||
# Format each line as "Coin: XX.XX%"
|
||||
result += f"- {coin.upper()}: {percentage:.2f}%\n"
|
||||
return result
|
||||
return result
|
||||
|
|
|
|||
|
|
@ -1,10 +1,27 @@
|
|||
from openai import OpenAI
|
||||
from .config import get_config
|
||||
|
||||
_client = None
|
||||
|
||||
def get_openai_client():
|
||||
"""Get or create OpenAI client with lazy initialization."""
|
||||
global _client
|
||||
if _client is None:
|
||||
try:
|
||||
config = get_config()
|
||||
base_url = config.get("backend_url")
|
||||
if not base_url:
|
||||
raise ValueError("backend_url not found in configuration")
|
||||
_client = OpenAI(base_url=base_url)
|
||||
except Exception as e:
|
||||
print(f"ERROR: Failed to initialize OpenAI client: {e}")
|
||||
raise
|
||||
|
||||
return _client
|
||||
|
||||
def get_stock_news_openai(query, start_date, end_date):
|
||||
config = get_config()
|
||||
client = OpenAI(base_url=config["backend_url"])
|
||||
client = get_openai_client()
|
||||
|
||||
response = client.responses.create(
|
||||
model=config["quick_think_llm"],
|
||||
|
|
@ -39,7 +56,7 @@ def get_stock_news_openai(query, start_date, end_date):
|
|||
|
||||
def get_crypto_news_openai(query, start_date, end_date):
|
||||
config = get_config()
|
||||
client = OpenAI(base_url=config["backend_url"])
|
||||
client = get_openai_client()
|
||||
|
||||
response = client.responses.create(
|
||||
model=config["quick_think_llm"],
|
||||
|
|
@ -74,7 +91,7 @@ def get_crypto_news_openai(query, start_date, end_date):
|
|||
|
||||
def get_global_news_openai(curr_date, look_back_days=7, limit=5):
|
||||
config = get_config()
|
||||
client = OpenAI(base_url=config["backend_url"])
|
||||
client = get_openai_client()
|
||||
|
||||
response = client.responses.create(
|
||||
model=config["quick_think_llm"],
|
||||
|
|
@ -110,7 +127,7 @@ def get_global_news_openai(curr_date, look_back_days=7, limit=5):
|
|||
|
||||
def get_fundamentals_openai(ticker, curr_date):
|
||||
config = get_config()
|
||||
client = OpenAI(base_url=config["backend_url"])
|
||||
client = get_openai_client()
|
||||
|
||||
response = client.responses.create(
|
||||
model=config["quick_think_llm"],
|
||||
|
|
@ -146,7 +163,7 @@ def get_fundamentals_openai(ticker, curr_date):
|
|||
|
||||
def get_whitepaper_openai(symbol):
|
||||
config = get_config()
|
||||
client = OpenAI(base_url=config["backend_url"])
|
||||
client = get_openai_client()
|
||||
|
||||
response = client.responses.create(
|
||||
model=config["quick_think_llm"],
|
||||
|
|
@ -177,4 +194,4 @@ def get_whitepaper_openai(symbol):
|
|||
store=True,
|
||||
)
|
||||
|
||||
return response.output[1].content[0].text
|
||||
return response.output[1].content[0].text
|
||||
|
|
|
|||
|
|
@ -1,16 +1,7 @@
|
|||
import requests
|
||||
from typing import Annotated, List, Dict
|
||||
import os
|
||||
from typing import Annotated, List
|
||||
from tradingagents.dataflows.config import get_config
|
||||
|
||||
|
||||
def get_api_key() -> str:
|
||||
"""Retrieve the API key for TAAPI from environment variables."""
|
||||
api_key = os.getenv("TAAPI_API_KEY")
|
||||
if not api_key:
|
||||
raise ValueError("TAAPI_API_KEY environment variable is not set.")
|
||||
return api_key
|
||||
|
||||
# This is for single indicator, unused for now but kept for reference
|
||||
def get_crypto_stats_indicators_window(
|
||||
symbol: Annotated[str, "ticker symbol of the coin/asset"],
|
||||
|
|
@ -58,8 +49,10 @@ def get_crypto_stats_indicators_window(
|
|||
return f"Error: Indicator '{indicator}' is not supported. Please choose from: {list(supported_indicators.keys())}"
|
||||
|
||||
config = get_config()
|
||||
base_url = config["tool_providers"].get("TAAPI_BASE_URL", "https://api.taapi.io")
|
||||
api_key = get_api_key()
|
||||
base_url = config["external"].get("TAAPI_BASE_URL", "https://api.taapi.io")
|
||||
api_key = config["external"].get("TAAPI_API_KEY", "")
|
||||
if not api_key:
|
||||
return "Error: TAAPI_API_KEY is not set in the configuration."
|
||||
|
||||
# Set backtrack as requested
|
||||
backtrack = look_back_days
|
||||
|
|
@ -187,8 +180,10 @@ def get_crypto_stats_indicators(
|
|||
return f"Error: Indicators {invalid_indicators} are not supported. Please choose from: {list(supported_indicators.keys())}"
|
||||
|
||||
config = get_config()
|
||||
base_url = config["tool_providers"].get("TAAPI_BASE_URL", "https://api.taapi.io")
|
||||
api_key = get_api_key()
|
||||
base_url = config["external"].get("TAAPI_BASE_URL", "https://api.taapi.io")
|
||||
api_key = config["external"].get("TAAPI_API_KEY", "")
|
||||
if not api_key:
|
||||
return "Error: TAAPI_API_KEY is not set in the configuration."
|
||||
|
||||
# Construct the bulk API URL
|
||||
url = f"{base_url}/bulk"
|
||||
|
|
|
|||
|
|
@ -1,13 +1,19 @@
|
|||
import asyncio
|
||||
from telethon import TelegramClient
|
||||
from datetime import datetime, timedelta, timezone
|
||||
import os
|
||||
from tradingagents.dataflows.config import get_config
|
||||
|
||||
def get_api_credentials():
|
||||
api_id = int(os.getenv("TELEGRAM_API_ID", ""))
|
||||
api_hash = os.getenv("TELEGRAM_API_HASH", "")
|
||||
session_name = os.getenv("TELEGRAM_SESSION_NAME", "")
|
||||
return api_id, api_hash, session_name
|
||||
"""Retrieve Telegram API credentials from environment variables."""
|
||||
config = get_config()
|
||||
api_id = config["external"]["TELEGRAM_API_ID"]
|
||||
api_hash = config["external"]["TELEGRAM_API_HASH"]
|
||||
session_name = config["external"]["TELEGRAM_SESSION_NAME"]
|
||||
|
||||
if not api_id or not api_hash or not session_name:
|
||||
raise ValueError("Missing required Telegram credentials: TELEGRAM_API_ID, TELEGRAM_API_HASH, or TELEGRAM_SESSION_NAME")
|
||||
|
||||
return int(api_id), api_hash, session_name
|
||||
|
||||
async def _get_channel_history_async(start_date_str, end_date_str):
|
||||
"""
|
||||
|
|
@ -55,4 +61,4 @@ def get_crypto_news_telegram(curr_date, look_back_days=7, limit=100):
|
|||
|
||||
start_date_str = start_date.strftime('%Y-%m-%d')
|
||||
end_date_str = end_date.strftime('%Y-%m-%d')
|
||||
return asyncio.run(_get_channel_history_async(start_date_str, end_date_str))
|
||||
return asyncio.run(_get_channel_history_async(start_date_str, end_date_str))
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
import os
|
||||
|
||||
DEFAULT_CONFIG = {
|
||||
# App config
|
||||
"APP_HOST": "localhost",
|
||||
"APP_PORT": 8000,
|
||||
# Directory settings
|
||||
"project_dir": os.path.abspath(os.path.join(os.path.dirname(__file__), ".")),
|
||||
"results_dir": os.getenv("TRADINGAGENTS_RESULTS_DIR", "./results"),
|
||||
"data_dir": "/Users/yluo/Documents/Code/ScAI/FR1-data",
|
||||
|
|
@ -9,10 +13,10 @@ DEFAULT_CONFIG = {
|
|||
"dataflows/data_cache",
|
||||
),
|
||||
# LLM settings
|
||||
"llm_provider": "openai",
|
||||
"deep_think_llm": "o4-mini",
|
||||
"quick_think_llm": "gpt-4o-mini",
|
||||
"backend_url": "https://api.openai.com/v1",
|
||||
"llm_provider": os.getenv("LLM_PROVIDER", "openai"),
|
||||
"deep_think_llm": os.getenv("DEEP_THINK_LLM", "gpt-4o-mini"),
|
||||
"quick_think_llm": os.getenv("QUICK_THINK_LLM", "gpt-4o-mini"),
|
||||
"backend_url": os.getenv("BACKEND_URL","https://api.openai.com/v1"),
|
||||
# Debate and discussion settings
|
||||
"max_debate_rounds": 1,
|
||||
"max_risk_discuss_rounds": 1,
|
||||
|
|
@ -29,7 +33,6 @@ DEFAULT_CONFIG = {
|
|||
},
|
||||
# Tool-level configuration (takes precedence over category-level)
|
||||
"tool_vendors": {
|
||||
# Example: "get_stock_data": "alpha_vantage", # Override category default
|
||||
"get_global_news": "telegram" # Override category default
|
||||
},
|
||||
# Tool provider settings
|
||||
|
|
@ -37,8 +40,21 @@ DEFAULT_CONFIG = {
|
|||
"TAAPI_BASE_URL": os.getenv("TAAPI_BASE_URL", "https://api.taapi.io"),
|
||||
},
|
||||
"external": {
|
||||
"BINANCE_API_KEY": os.getenv("BINANCE_API_KEY", ""),
|
||||
"TAAPI_BASE_URL": os.getenv("TAAPI_BASE_URL", "https://api.taapi.io"),
|
||||
"TAAPI_API_KEY": os.getenv("TAAPI_API_KEY", ""),
|
||||
"BYBIT_BASE_URL": os.getenv("BYBIT_BASE_URL", "https://api-demo.bybit.com"),
|
||||
"BYBIT_API_KEY": os.getenv("BYBIT_API_KEY", ""),
|
||||
"BYBIT_API_SECRET": os.getenv("BYBIT_API_SECRET", ""),
|
||||
}
|
||||
"COIN_GECKO_API_BASE_URL": os.getenv("COIN_GECKO_API_BASE_URL", "https://api.coingecko.com/api/v3"),
|
||||
"TELEGRAM_API_ID": os.getenv("TELEGRAM_API_ID", ""),
|
||||
"TELEGRAM_API_HASH": os.getenv("TELEGRAM_API_HASH", ""),
|
||||
"TELEGRAM_SESSION_NAME": os.getenv("TELEGRAM_SESSION_NAME", ""),
|
||||
},
|
||||
"redis": {
|
||||
"REDIS_HOST": os.getenv("REDIS_HOST", "localhost"),
|
||||
"REDIS_PORT": int(os.getenv("REDIS_PORT", 6379)),
|
||||
"REDIS_PASSWORD": os.getenv("REDIS_PASSWORD", "defaultpassword"),
|
||||
"REDIS_DB": int(os.getenv("REDIS_DB", 0)),
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
from redis import Redis, ConnectionPool
|
||||
from redis.backoff import ExponentialBackoff
|
||||
from redis.retry import Retry
|
||||
from tradingagents.dataflows.config import get_config
|
||||
|
||||
_client = None
|
||||
|
||||
def get_redis_client() -> Redis:
|
||||
"""Get or create Redis client with lazy initialization."""
|
||||
global _client
|
||||
if _client is None:
|
||||
try:
|
||||
config = get_config()
|
||||
retry = Retry(ExponentialBackoff(), retries=5)
|
||||
|
||||
pool = ConnectionPool(
|
||||
host=config["redis"]["REDIS_HOST"],
|
||||
port=config["redis"]["REDIS_PORT"],
|
||||
password=config["redis"]["REDIS_PASSWORD"],
|
||||
db=config["redis"]["REDIS_DB"],
|
||||
decode_responses=True,
|
||||
socket_connect_timeout=5,
|
||||
socket_timeout=5,
|
||||
health_check_interval=10,
|
||||
retry=retry,
|
||||
)
|
||||
print("INFO: Initializing Redis client")
|
||||
_client = Redis(connection_pool=pool)
|
||||
print("INFO: Redis client initialized successfully")
|
||||
except Exception as e:
|
||||
print(f"ERROR: Failed to initialize Redis client: {e}")
|
||||
raise
|
||||
|
||||
return _client
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
from tradingagents.external.redis.client import get_redis_client
|
||||
|
||||
redis = get_redis_client()
|
||||
|
||||
class RedisRepo:
|
||||
def get(self, key: str):
|
||||
return redis.get(key)
|
||||
|
||||
def set(self, key: str, value: str, ex: int | None = None):
|
||||
return redis.set(key, value, ex=ex)
|
||||
|
||||
def delete(self, key: str):
|
||||
return redis.delete(key)
|
||||
|
||||
def exists(self, key: str) -> bool:
|
||||
return redis.exists(key) == 1
|
||||
|
||||
redis_repo = RedisRepo()
|
||||
|
|
@ -21,7 +21,6 @@ class Propagator:
|
|||
"""Create the initial state for the agent graph."""
|
||||
return {
|
||||
"messages": [("human", ticker)],
|
||||
"company_of_interest": ticker,
|
||||
"ticker_of_interest": ticker,
|
||||
"trade_date": str(trade_date),
|
||||
"investment_debate_state": InvestDebateState(
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ class TradingAgentsGraph:
|
|||
def _log_state(self, trade_date, final_state):
|
||||
"""Log the final state to a JSON file."""
|
||||
self.log_states_dict[str(trade_date)] = {
|
||||
"company_of_interest": final_state["company_of_interest"],
|
||||
"ticker_of_interest": final_state["ticker_of_interest"],
|
||||
"trade_date": final_state["trade_date"],
|
||||
"market_report": final_state["market_report"],
|
||||
"sentiment_report": final_state["sentiment_report"],
|
||||
|
|
|
|||
|
|
@ -0,0 +1,105 @@
|
|||
from fastapi import FastAPI, HTTPException
|
||||
from pydantic import BaseModel
|
||||
import uvicorn
|
||||
from datetime import datetime
|
||||
import asyncio
|
||||
|
||||
# Import your trading agents
|
||||
from tradingagents.graph.trading_graph import TradingAgentsGraph
|
||||
from tradingagents.dataflows.config import get_config
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Load environment variables
|
||||
load_dotenv()
|
||||
|
||||
config = get_config()
|
||||
|
||||
# Create FastAPI app instance
|
||||
app = FastAPI(
|
||||
title="TradingAgents API",
|
||||
description="API for TradingAgents financial trading framework",
|
||||
version="0.1.0"
|
||||
)
|
||||
|
||||
# Pydantic models for request/response
|
||||
class TradingRequest(BaseModel):
|
||||
symbol: str
|
||||
date: str
|
||||
|
||||
class TradingResponse(BaseModel):
|
||||
symbol: str
|
||||
date: str
|
||||
decision: dict
|
||||
timestamp: str
|
||||
status: str
|
||||
|
||||
# Initialize trading agent once at startup
|
||||
def create_trading_agent():
|
||||
"""Create trading agent with fixed configuration"""
|
||||
return TradingAgentsGraph(debug=True, config=config)
|
||||
|
||||
# Create the trading agent instance once
|
||||
trading_agent = create_trading_agent()
|
||||
|
||||
@app.get("/")
|
||||
async def root():
|
||||
"""Root endpoint"""
|
||||
return {"message": "Welcome to TradingAgents API"}
|
||||
|
||||
@app.get("/ping")
|
||||
async def ping():
|
||||
"""Simple ping endpoint that returns pong"""
|
||||
return {"message": "pong"}
|
||||
|
||||
@app.get("/health")
|
||||
async def health_check():
|
||||
"""Health check endpoint"""
|
||||
return {
|
||||
"status": "healthy",
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"service": "tradingagents-api"
|
||||
}
|
||||
|
||||
@app.post("/trading/analyze", response_model=TradingResponse)
|
||||
async def analyze_trading_decision(request: TradingRequest):
|
||||
"""
|
||||
Analyze trading decision for a given symbol and date
|
||||
|
||||
Example usage:
|
||||
POST /trading/analyze
|
||||
{
|
||||
"symbol": "NVDA",
|
||||
"date": "2024-05-10"
|
||||
}
|
||||
"""
|
||||
try:
|
||||
# Run the analysis (this might take a while, so we run it in a thread pool)
|
||||
def run_analysis():
|
||||
_, decision = trading_agent.propagate(request.symbol, request.date)
|
||||
return decision
|
||||
|
||||
# Run in thread pool to avoid blocking
|
||||
loop = asyncio.get_event_loop()
|
||||
decision = await loop.run_in_executor(None, run_analysis)
|
||||
|
||||
return TradingResponse(
|
||||
symbol=request.symbol,
|
||||
date=request.date,
|
||||
decision=decision,
|
||||
timestamp=datetime.now().isoformat(),
|
||||
status="success"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Trading analysis failed: {str(e)}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Run the server
|
||||
uvicorn.run(
|
||||
"webapp:app",
|
||||
host=config.get("APP_HOST", "localhost"),
|
||||
port=config.get("APP_PORT", 8000),
|
||||
reload=True,
|
||||
log_level="info"
|
||||
)
|
||||
Loading…
Reference in New Issue