feat: add fear and greed index dataflow

feat: add Binance single OHLCV for analysts
This commit is contained in:
Tomortec 2025-07-01 18:14:06 +08:00
parent 630e06f512
commit 1712851a07
9 changed files with 132 additions and 9 deletions

View File

@ -11,6 +11,7 @@ def create_fundamentals_analyst(llm, toolkit):
company_name = state["company_of_interest"] company_name = state["company_of_interest"]
tools = [ tools = [
toolkit.get_binance_ohlcv,
toolkit.get_fundamentals_openai toolkit.get_fundamentals_openai
] ]

View File

@ -10,11 +10,13 @@ def create_news_analyst(llm, toolkit):
ticker = state["company_of_interest"] ticker = state["company_of_interest"]
tools = [ tools = [
toolkit.get_binance_ohlcv,
# toolkit.get_global_news_openai, # toolkit.get_global_news_openai,
# toolkit.get_google_news, # toolkit.get_google_news,
# toolkit.get_reddit_news, # toolkit.get_reddit_news,
toolkit.get_blockbeats_news, toolkit.get_blockbeats_news,
toolkit.get_coindesk_news, toolkit.get_coindesk_news,
toolkit.get_fear_and_greed_index
] ]
system_message = ( system_message = (

View File

@ -11,8 +11,10 @@ def create_social_media_analyst(llm, toolkit):
company_name = state["company_of_interest"] company_name = state["company_of_interest"]
tools = [ tools = [
toolkit.get_stock_news_openai, toolkit.get_binance_ohlcv,
toolkit.get_reddit_stock_info toolkit.get_fear_and_greed_index,
# toolkit.get_stock_news_openai,
# toolkit.get_reddit_stock_info
] ]
system_message = ( system_message = (

View File

@ -83,6 +83,26 @@ class Toolkit:
coindesk_news_result = interface.get_coindesk_news(tickers, count) coindesk_news_result = interface.get_coindesk_news(tickers, count)
return coindesk_news_result 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 @staticmethod
@tool @tool
def get_binance_data( def get_binance_data(
@ -103,6 +123,16 @@ class Toolkit:
binance_data_result = interface.get_binance_data(symbol, interval) binance_data_result = interface.get_binance_data(symbol, interval)
return binance_data_result 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 @staticmethod
@tool @tool
def get_reddit_news( def get_reddit_news(

View File

@ -5,10 +5,12 @@ from .binance_utils import *
from .reddit_utils import fetch_top_from_category from .reddit_utils import fetch_top_from_category
from .interface import ( from .interface import (
get_binance_ohlcv,
# News and sentiment functions # News and sentiment functions
get_blockbeats_news, get_blockbeats_news,
get_coindesk_news, get_coindesk_news,
get_google_news, get_google_news,
get_fear_and_greed_index,
get_reddit_global_news, get_reddit_global_news,
get_reddit_company_news, get_reddit_company_news,
# Financial statements functions # Financial statements functions
@ -20,10 +22,12 @@ from .interface import (
) )
__all__ = [ __all__ = [
"get_binance_ohlcv",
# News and sentiment functions # News and sentiment functions
"get_blockbeats_news", "get_blockbeats_news",
"get_coindesk_news", "get_coindesk_news",
"get_google_news", "get_google_news",
"get_fear_and_greed_index",
"get_reddit_global_news", "get_reddit_global_news",
"get_reddit_company_news", "get_reddit_company_news",
# Financial statements functions # Financial statements functions

View File

@ -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]

View File

@ -3,6 +3,35 @@ from binance.um_futures import UMFutures
um_futures_client = 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): def fetch_klines_from_binance(symbol: str, interval: str, limit: int = 75):
""" """
Fetch historical klines (candlestick data) from Binance. 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) return um_futures_client.klines(symbol=symbol, interval=interval, limit=limit)
@check_symbol
def fetch_depth_from_binance(symbol: str, limit: int = 50): def fetch_depth_from_binance(symbol: str, limit: int = 50):
""" """
Fetch the order book depth from Binance. 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) return um_futures_client.depth(symbol=symbol, limit=limit)
@check_symbol
def fetch_24hr_pricechange_from_binance(symbol: str): def fetch_24hr_pricechange_from_binance(symbol: str):
""" """
Fetch 24-hour ticker price change statistics from Binance. 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) 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): def fetch_toplongshort_position_ratio_from_binance(symbol: str, period: str, limit: int = 50):
""" """
Fetch the top long/short position ratio from Binance. 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) 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): def fetch_toplongshort_account_ratio_from_binance(symbol: str, period: str, limit: int = 50):
""" """
Fetch the top long/short account ratio from Binance. 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) 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): def fetch_global_longshort_account_ratio_from_binance(symbol: str, period: str, limit: int = 50):
""" """
Fetch the global long/short account ratio from Binance. 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) 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): def fetch_taker_longshort_ratio_from_binance(symbol: str, period: str, limit: int = 50):
""" """
Fetch the taker long/short ratio from Binance. Fetch the taker long/short ratio from Binance.

View File

@ -2,11 +2,9 @@ from typing import Annotated, Dict
from .blockbeats_utils import fetch_news_from_blockbeats from .blockbeats_utils import fetch_news_from_blockbeats
from .coindesk_utils import fetch_news_from_coindesk from .coindesk_utils import fetch_news_from_coindesk
from .reddit_utils import fetch_top_from_category from .reddit_utils import fetch_top_from_category
from .yfin_utils import *
from .stockstats_utils import *
from .googlenews_utils import * from .googlenews_utils import *
from .binance_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 dateutil.relativedelta import relativedelta
from concurrent.futures import ThreadPoolExecutor from concurrent.futures import ThreadPoolExecutor
from datetime import datetime from datetime import datetime
@ -14,10 +12,14 @@ import json
import os import os
import pandas as pd import pandas as pd
from tqdm import tqdm from tqdm import tqdm
import yfinance as yf
from openai import OpenAI from openai import OpenAI
from .config import get_config, set_config, DATA_DIR from .config import get_config, set_config, DATA_DIR
from warnings import deprecated 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): 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}" 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( def get_google_news(
query: Annotated[str, "Query to search with"], query: Annotated[str, "Query to search with"],
curr_date: Annotated[str, "Curr date in yyyy-mm-dd format"], 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}" 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( def get_binance_data(
symbol: Annotated[str, "ticker symbol of the asset"], symbol: Annotated[str, "ticker symbol of the asset"],
interval: Annotated[str, "time interval for the data, e.g., '1m', '5m', '1h'"], interval: Annotated[str, "time interval for the data, e.g., '1m', '5m', '1h'"],

View File

@ -122,12 +122,15 @@ class TradingAgentsGraph:
), ),
"social": ToolNode( "social": ToolNode(
[ [
self.toolkit.get_stock_news_openai, self.toolkit.get_binance_ohlcv,
self.toolkit.get_reddit_stock_info, self.toolkit.get_fear_and_greed_index,
# self.toolkit.get_stock_news_openai,
# self.toolkit.get_reddit_stock_info,
] ]
), ),
"news": ToolNode( "news": ToolNode(
[ [
self.toolkit.get_binance_ohlcv,
# self.toolkit.get_global_news_openai, # self.toolkit.get_global_news_openai,
# self.toolkit.get_google_news, # self.toolkit.get_google_news,
self.toolkit.get_blockbeats_news, self.toolkit.get_blockbeats_news,
@ -137,6 +140,7 @@ class TradingAgentsGraph:
), ),
"fundamentals": ToolNode( "fundamentals": ToolNode(
[ [
self.toolkit.get_binance_ohlcv,
self.toolkit.get_fundamentals_openai self.toolkit.get_fundamentals_openai
] ]
), ),