diff --git a/.env.example b/.env.example index ca3762c6..076b45a4 100644 --- a/.env.example +++ b/.env.example @@ -2,4 +2,5 @@ ALPHA_VANTAGE_API_KEY=alpha_vantage_api_key_placeholder OPENAI_API_KEY=openai_api_key_placeholder TELEGRAM_API_ID=telegram_api_placeholder TELEGRAM_API_HASH=telegram_api_hash_placeholder -TELEGRAM_SESSION_NAME=telegram_session_name_placeholder \ No newline at end of file +TELEGRAM_SESSION_NAME=telegram_session_name_placeholder +BINANCE_API_KEY=binance_api_key_placeholder diff --git a/.gitignore b/.gitignore index acf60dc8..d9c9053b 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ eval_data/ *.egg-info/ .env .python-version +playground.ipynb diff --git a/requirements.txt b/requirements.txt index a6154cd2..4849c721 100644 --- a/requirements.txt +++ b/requirements.txt @@ -24,3 +24,4 @@ rich questionary langchain_anthropic langchain-google-genai +binance-sdk-spot diff --git a/tradingagents/agents/utils/agent_utils.py b/tradingagents/agents/utils/agent_utils.py index 2d74fbbc..0564c90f 100644 --- a/tradingagents/agents/utils/agent_utils.py +++ b/tradingagents/agents/utils/agent_utils.py @@ -1,6 +1,9 @@ from langchain_core.messages import HumanMessage, RemoveMessage # Import tools from separate utility files +from tradingagents.agents.utils.core_crypto_tools import ( + get_crypto_data +) from tradingagents.agents.utils.core_stock_tools import ( get_stock_data ) diff --git a/tradingagents/agents/utils/core_crypto_tools.py b/tradingagents/agents/utils/core_crypto_tools.py new file mode 100644 index 00000000..6b06ecea --- /dev/null +++ b/tradingagents/agents/utils/core_crypto_tools.py @@ -0,0 +1,21 @@ +from langchain_core.tools import tool +from typing import Annotated +from tradingagents.dataflows.interface import route_to_vendor + +@tool +def get_crypto_data( + symbol: Annotated[str, "trading symbol, e.g., BTCUSDT"], + start_date: Annotated[str, "Start date in yyyy-mm-dd format"], + end_date: Annotated[str, "End date in yyyy-mm-dd format"], +) -> str: + """ + Retrieve cryptocurrency price data (OHLCV) for a given trading symbol. + Uses the configured core_crypto_apis vendor. + Args: + symbol (str): Trading symbol, e.g., BTCUSDT + start_date (str): Start date in yyyy-mm-dd format + end_date (str): End date in yyyy-mm-dd format + Returns: + str: A formatted dataframe containing the cryptocurrency price data for the specified trading symbol in the specified date range. + """ + return route_to_vendor("get_crypto_data", symbol, start_date, end_date) diff --git a/tradingagents/dataflows/binance.py b/tradingagents/dataflows/binance.py new file mode 100644 index 00000000..f3eda7cc --- /dev/null +++ b/tradingagents/dataflows/binance.py @@ -0,0 +1,85 @@ +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 + +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 + +configuration = ConfigurationRestAPI(api_key=get_api_key(), base_path=SPOT_REST_API_PROD_URL) +client = Spot(config_rest_api=configuration) + +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. + + Args: + symbol: Trading symbol (e.g., 'BTCUSDT') + start_date: Start date in YYYY-MM-DD format + end_date: End date in YYYY-MM-DD format + + Returns: + CSV formatted string with OHLCV data + """ + # Convert dates to epoch time (milliseconds) + start_epoch = int(datetime.strptime(start_date, "%Y-%m-%d").timestamp() * 1000) + end_epoch = int(datetime.strptime(end_date, "%Y-%m-%d").timestamp() * 1000) + + print(f"DEBUG: Fetching data for {symbol} from {start_date} to {end_date}") + try: + response = client.rest_api.klines( + symbol=symbol, + start_time=start_epoch, + end_time=end_epoch, + interval="1d", + ) + + rate_limits = response.rate_limits + print(f"DEBUG: klines() rate limits: {rate_limits}") + + data = response.data() + + # Convert to CSV format + if not data: + return "No data available" + + # Create CSV string + output = io.StringIO() + writer = csv.writer(output) + + # Write headers + headers = [ + "Open Time", + "Open Price", + "High Price", + "Low Price", + "Close Price", + "Volume", + "Close Time", + "Quote Asset Volume", + "Number of Trades", + "Taker Buy Base Asset Volume", + "Taker Buy Quote Asset Volume", + "Unused Field" + ] + writer.writerow(headers) + + # Write data rows + for row in data: + writer.writerow(row) + + csv_string = output.getvalue() + output.close() + + return csv_string + + except Exception as e: + print(f"ERROR: klines() error: {e}") + return f"Error fetching market data from Binance: {e}" + diff --git a/tradingagents/dataflows/interface.py b/tradingagents/dataflows/interface.py index d8b89057..28c64b43 100644 --- a/tradingagents/dataflows/interface.py +++ b/tradingagents/dataflows/interface.py @@ -17,12 +17,19 @@ from .alpha_vantage import ( ) from .alpha_vantage_common import AlphaVantageRateLimitError from .telegram import get_crypto_news_telegram +from .binance import get_market_data as get_binance_crypto_data # Configuration and routing logic from .config import get_config # Tools organized by category TOOLS_CATEGORIES = { + "core_crypto_apis": { + "description": "OHLCV cryptocurrency price data", + "tools": [ + "get_crypto_data" + ] + }, "core_stock_apis": { "description": "OHLCV stock price data", "tools": [ @@ -65,6 +72,10 @@ VENDOR_LIST = [ # Mapping of methods to their vendor-specific implementations VENDOR_METHODS = { + # core_crypto_apis + "get_crypto_data": { + "binance": get_binance_crypto_data, + }, # core_stock_apis "get_stock_data": { "alpha_vantage": get_alpha_vantage_stock, @@ -247,4 +258,4 @@ def route_to_vendor(method: str, *args, **kwargs): return results[0] else: # Convert all results to strings and concatenate - return '\n'.join(str(result) for result in results) \ No newline at end of file + return '\n'.join(str(result) for result in results) diff --git a/tradingagents/default_config.py b/tradingagents/default_config.py index 1f40a2a2..08b18cc1 100644 --- a/tradingagents/default_config.py +++ b/tradingagents/default_config.py @@ -20,6 +20,7 @@ DEFAULT_CONFIG = { # Data vendor configuration # Category-level configuration (default for all tools in category) "data_vendors": { + "core_crypto_apis": "binance", # Options: binance "core_stock_apis": "yfinance", # Options: yfinance, alpha_vantage, local "technical_indicators": "yfinance", # Options: yfinance, alpha_vantage, local "fundamental_data": "alpha_vantage", # Options: openai, alpha_vantage, local