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"]
tools = [
toolkit.get_binance_ohlcv,
toolkit.get_fundamentals_openai
]

View File

@ -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 = (

View File

@ -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 = (

View File

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

View File

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

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()
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.

View File

@ -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'"],

View File

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