diff --git a/tradingagents/agents/analysts/fundamentals_analyst.py b/tradingagents/agents/analysts/fundamentals_analyst.py index aef2fbda..ba5ac646 100644 --- a/tradingagents/agents/analysts/fundamentals_analyst.py +++ b/tradingagents/agents/analysts/fundamentals_analyst.py @@ -11,6 +11,7 @@ def create_fundamentals_analyst(llm, toolkit): company_name = state["company_of_interest"] tools = [ + toolkit.get_binance_ohlcv, toolkit.get_fundamentals_openai ] diff --git a/tradingagents/agents/analysts/news_analyst.py b/tradingagents/agents/analysts/news_analyst.py index 9f9dda4b..3f3d3254 100644 --- a/tradingagents/agents/analysts/news_analyst.py +++ b/tradingagents/agents/analysts/news_analyst.py @@ -10,11 +10,13 @@ def create_news_analyst(llm, toolkit): ticker = state["company_of_interest"] tools = [ + toolkit.get_binance_ohlcv, # toolkit.get_global_news_openai, # toolkit.get_google_news, # toolkit.get_reddit_news, toolkit.get_blockbeats_news, toolkit.get_coindesk_news, + toolkit.get_fear_and_greed_index ] system_message = ( diff --git a/tradingagents/agents/analysts/social_media_analyst.py b/tradingagents/agents/analysts/social_media_analyst.py index abcebaa7..20d63c86 100644 --- a/tradingagents/agents/analysts/social_media_analyst.py +++ b/tradingagents/agents/analysts/social_media_analyst.py @@ -11,8 +11,10 @@ def create_social_media_analyst(llm, toolkit): company_name = state["company_of_interest"] tools = [ - toolkit.get_stock_news_openai, - toolkit.get_reddit_stock_info + toolkit.get_binance_ohlcv, + toolkit.get_fear_and_greed_index, + # toolkit.get_stock_news_openai, + # toolkit.get_reddit_stock_info ] system_message = ( diff --git a/tradingagents/agents/utils/agent_utils.py b/tradingagents/agents/utils/agent_utils.py index d04669af..91e4231b 100644 --- a/tradingagents/agents/utils/agent_utils.py +++ b/tradingagents/agents/utils/agent_utils.py @@ -83,6 +83,26 @@ class Toolkit: coindesk_news_result = interface.get_coindesk_news(tickers, count) return coindesk_news_result + @staticmethod + @tool + def get_binance_ohlcv( + symbol: Annotated[str, "ticker symbol of the asset"], + interval: Annotated[ + str, + "Interval for the data, e.g. '1m', '5m', '1h', '1d'", + ] = "15m", + ) -> str: + """ + Retrieve the latest OHLCV data from Binance for a given symbol and interval. + Args: + symbol (str): Ticker symbol of the asset, e.g. 'BTCUSDT' + interval (str): Interval for the data, e.g. '1m', '5m', '1h', '1d' + Returns: + str: A formatted string containing the latest OHLCV data from Binance for the specified symbol and interval. + """ + binance_ohlcv_result = interface.get_binance_ohlcv(symbol, interval) + return binance_ohlcv_result + @staticmethod @tool def get_binance_data( @@ -102,7 +122,17 @@ class Toolkit: """ binance_data_result = interface.get_binance_data(symbol, interval) return binance_data_result - + + @staticmethod + @tool + def get_fear_and_greed_index() -> str: + """ + Get current crypto market Fear and Greed Index. 0 means "Extreme Fear", while 100 means "Extreme Greed" + Returns: + str: A formatted string containing the current crypto market Fear and Greed Index. + """ + return interface.get_fear_and_greed_index() + @staticmethod @tool def get_reddit_news( diff --git a/tradingagents/dataflows/__init__.py b/tradingagents/dataflows/__init__.py index 0bb70233..b80eb563 100644 --- a/tradingagents/dataflows/__init__.py +++ b/tradingagents/dataflows/__init__.py @@ -5,10 +5,12 @@ from .binance_utils import * from .reddit_utils import fetch_top_from_category from .interface import ( + get_binance_ohlcv, # News and sentiment functions get_blockbeats_news, get_coindesk_news, get_google_news, + get_fear_and_greed_index, get_reddit_global_news, get_reddit_company_news, # Financial statements functions @@ -20,10 +22,12 @@ from .interface import ( ) __all__ = [ + "get_binance_ohlcv", # News and sentiment functions "get_blockbeats_news", "get_coindesk_news", "get_google_news", + "get_fear_and_greed_index", "get_reddit_global_news", "get_reddit_company_news", # Financial statements functions diff --git a/tradingagents/dataflows/alternativeme_utils.py b/tradingagents/dataflows/alternativeme_utils.py new file mode 100644 index 00000000..608b4887 --- /dev/null +++ b/tradingagents/dataflows/alternativeme_utils.py @@ -0,0 +1,15 @@ + +import requests + +def fetch_fear_and_greed_from_alternativeme(): + """ + Fetch the Fear and Greed Index from Alternative.me API. + Returns: + list[str]: A list of fear and greed index values. Sorted by date in descending order. + """ + url = "https://api.alternative.me/fng/?limit=10" + response = requests.get(url) + if response.status_code == 200: + data = response.json() + if "data" in data and len(data["data"]) > 0: + return [value["value"] for value in data["data"] if "value" in value] \ No newline at end of file diff --git a/tradingagents/dataflows/binance_utils.py b/tradingagents/dataflows/binance_utils.py index b3af8a6a..d44ff73c 100644 --- a/tradingagents/dataflows/binance_utils.py +++ b/tradingagents/dataflows/binance_utils.py @@ -3,6 +3,35 @@ from binance.um_futures import UMFutures um_futures_client = UMFutures() +def check_symbol(fn): + def wrapper(symbol: str, *args, **kwargs): + symbol = symbol.upper() + if not symbol.endswith("USDT") and not symbol.endswith("USDC"): + symbol += "USDT" + return fn(symbol, *args, **kwargs) + return wrapper + +@check_symbol +def fetch_ohlcv_from_binance(symbol: str, interval: str): + """ + Fetch historical OHLCV (Open, High, Low, Close, Volume) data from Binance. + + :param symbol: The trading pair symbol (e.g., 'BTCUSDT'). + :param interval: The time interval for the OHLCV data (e.g., '1m', '5m', '1h'). + :return: A dictionary containing the latest OHLCV data. + """ + data = um_futures_client.klines(symbol=symbol, interval=interval, limit=1) + if isinstance(data, list) and len(data) > 0: + ohlcv = data[0] + return { + "open": float(ohlcv[1]), + "high": float(ohlcv[2]), + "low": float(ohlcv[3]), + "close": float(ohlcv[4]), + "volume": float(ohlcv[5]) + } + +@check_symbol def fetch_klines_from_binance(symbol: str, interval: str, limit: int = 75): """ Fetch historical klines (candlestick data) from Binance. @@ -14,6 +43,7 @@ def fetch_klines_from_binance(symbol: str, interval: str, limit: int = 75): """ return um_futures_client.klines(symbol=symbol, interval=interval, limit=limit) +@check_symbol def fetch_depth_from_binance(symbol: str, limit: int = 50): """ Fetch the order book depth from Binance. @@ -24,6 +54,7 @@ def fetch_depth_from_binance(symbol: str, limit: int = 50): """ return um_futures_client.depth(symbol=symbol, limit=limit) +@check_symbol def fetch_24hr_pricechange_from_binance(symbol: str): """ Fetch 24-hour ticker price change statistics from Binance. @@ -33,6 +64,7 @@ def fetch_24hr_pricechange_from_binance(symbol: str): """ return um_futures_client.ticker_24hr_price_change(symbol=symbol) +@check_symbol def fetch_toplongshort_position_ratio_from_binance(symbol: str, period: str, limit: int = 50): """ Fetch the top long/short position ratio from Binance. @@ -44,6 +76,7 @@ def fetch_toplongshort_position_ratio_from_binance(symbol: str, period: str, lim """ return um_futures_client.top_long_short_position_ratio(symbol=symbol, period=period, limit=limit) +@check_symbol def fetch_toplongshort_account_ratio_from_binance(symbol: str, period: str, limit: int = 50): """ Fetch the top long/short account ratio from Binance. @@ -55,6 +88,7 @@ def fetch_toplongshort_account_ratio_from_binance(symbol: str, period: str, limi """ return um_futures_client.top_long_short_account_ratio(symbol=symbol, period=period, limit=limit) +@check_symbol def fetch_global_longshort_account_ratio_from_binance(symbol: str, period: str, limit: int = 50): """ Fetch the global long/short account ratio from Binance. @@ -66,6 +100,7 @@ def fetch_global_longshort_account_ratio_from_binance(symbol: str, period: str, """ return um_futures_client.long_short_account_ratio(symbol=symbol, period=period, limit=limit) +@check_symbol def fetch_taker_longshort_ratio_from_binance(symbol: str, period: str, limit: int = 50): """ Fetch the taker long/short ratio from Binance. diff --git a/tradingagents/dataflows/interface.py b/tradingagents/dataflows/interface.py index 36ecc541..b6578bd9 100644 --- a/tradingagents/dataflows/interface.py +++ b/tradingagents/dataflows/interface.py @@ -2,11 +2,9 @@ from typing import Annotated, Dict from .blockbeats_utils import fetch_news_from_blockbeats from .coindesk_utils import fetch_news_from_coindesk from .reddit_utils import fetch_top_from_category -from .yfin_utils import * -from .stockstats_utils import * from .googlenews_utils import * from .binance_utils import * -from .finnhub_utils import get_data_in_range +from .alternativeme_utils import fetch_fear_and_greed_from_alternativeme from dateutil.relativedelta import relativedelta from concurrent.futures import ThreadPoolExecutor from datetime import datetime @@ -14,10 +12,14 @@ import json import os import pandas as pd from tqdm import tqdm -import yfinance as yf from openai import OpenAI from .config import get_config, set_config, DATA_DIR + from warnings import deprecated +from .yfin_utils import * +from .stockstats_utils import * +from .finnhub_utils import get_data_in_range +import yfinance as yf def get_blockbeats_news(count: Annotated[int, "news' count, no more than 30"] = 10): """ @@ -66,6 +68,10 @@ def get_coindesk_news( return f"## Coindesk News:\n\n{news_str}" +def get_fear_and_greed_index() -> str: + fng = fetch_fear_and_greed_from_alternativeme() + return f"""## Fear and Greed Index: {fng[0]}\n0 means \"Extreme Fear\", while 100 means \"Extreme Greed\"\nPrevious daily FnG: {','.join(fng[1:])}""" + def get_google_news( query: Annotated[str, "Query to search with"], curr_date: Annotated[str, "Curr date in yyyy-mm-dd format"], @@ -200,6 +206,30 @@ def get_reddit_company_news( return f"##{ticker} News Reddit, from {before} to {curr_date}:\n\n{news_str}" +def get_binance_ohlcv( + symbol: Annotated[str, "ticker symbol of the asset"], + interval: Annotated[str, "time interval for the data, e.g., '1m', '5m', '1h'"], +) -> str: + """ + Fetch the latest OHLCV (Open, High, Low, Close, Volume) data from Binance for a given symbol and interval. + + Args: + symbol (str): The trading pair symbol (e.g., 'BTCUSDT'). + interval (str): The time interval for the OHLCV data (e.g., '1m', '5m', '1h'). + Returns: + str: A formatted string containing the latest OHLCV data. + """ + symbol = symbol.upper().strip() + if not symbol.endswith("USDT"): + symbol += "USDT" + + ohlcv = fetch_ohlcv_from_binance(symbol, interval) + if ohlcv is dict: + return ( + f"## {symbol} Futures **Latest OHLCV Data** in last {interval}:\n" + f"Open: {ohlcv['open']}, High: {ohlcv['high']}, Low: {ohlcv['low']}, Close: {ohlcv['close']}, Volume: {ohlcv['volume']}\n" + ) + def get_binance_data( symbol: Annotated[str, "ticker symbol of the asset"], interval: Annotated[str, "time interval for the data, e.g., '1m', '5m', '1h'"], diff --git a/tradingagents/graph/trading_graph.py b/tradingagents/graph/trading_graph.py index 26ec2f39..20026dae 100644 --- a/tradingagents/graph/trading_graph.py +++ b/tradingagents/graph/trading_graph.py @@ -122,12 +122,15 @@ class TradingAgentsGraph: ), "social": ToolNode( [ - self.toolkit.get_stock_news_openai, - self.toolkit.get_reddit_stock_info, + self.toolkit.get_binance_ohlcv, + self.toolkit.get_fear_and_greed_index, + # self.toolkit.get_stock_news_openai, + # self.toolkit.get_reddit_stock_info, ] ), "news": ToolNode( [ + self.toolkit.get_binance_ohlcv, # self.toolkit.get_global_news_openai, # self.toolkit.get_google_news, self.toolkit.get_blockbeats_news, @@ -137,6 +140,7 @@ class TradingAgentsGraph: ), "fundamentals": ToolNode( [ + self.toolkit.get_binance_ohlcv, self.toolkit.get_fundamentals_openai ] ),