feat: get crypto data from Binance

This commit is contained in:
Tomortec 2025-06-26 21:47:12 +08:00
parent 3e83389092
commit 375b09b0e9
10 changed files with 234 additions and 24 deletions

View File

@ -25,3 +25,4 @@ rich
questionary
langchain_anthropic
langchain-google-genai
binance-futures-connector

View File

@ -12,7 +12,7 @@ def create_market_analyst(llm, toolkit):
if toolkit.config["online_tools"]:
tools = [
toolkit.get_YFin_data_online,
toolkit.get_binance_data,
toolkit.get_stockstats_indicators_report_online,
]
else:

View File

@ -9,7 +9,12 @@ def create_news_analyst(llm, toolkit):
ticker = state["company_of_interest"]
if toolkit.config["online_tools"]:
tools = [toolkit.get_global_news_openai, toolkit.get_google_news]
tools = [
toolkit.get_global_news_openai,
toolkit.get_google_news,
toolkit.get_blockbeats_news,
toolkit.get_coindesk_news,
]
else:
tools = [
toolkit.get_finnhub_news,

View File

@ -82,6 +82,26 @@ class Toolkit:
"""
coindesk_news_result = interface.get_coindesk_news(tickers, count)
return coindesk_news_result
@staticmethod
@tool
def get_binance_data(
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 market 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 market data from Binance for the specified symbol and interval.
"""
binance_data_result = interface.get_binance_data(symbol, interval)
return binance_data_result
@staticmethod
@tool

View File

@ -3,6 +3,7 @@ from .coindesk_utils import get_coindesk_news
from .finnhub_utils import get_data_in_range
from .googlenews_utils import getNewsData
from .yfin_utils import YFinanceUtils
from .binance_utils import *
from .reddit_utils import fetch_top_from_category
from .stockstats_utils import StockstatsUtils
from .yfin_utils import YFinanceUtils
@ -27,6 +28,7 @@ from .interface import (
# Market data functions
get_YFin_data_window,
get_YFin_data,
get_binance_data
)
__all__ = [
@ -49,4 +51,5 @@ __all__ = [
# Market data functions
"get_YFin_data_window",
"get_YFin_data",
"get_binance_data"
]

View File

@ -0,0 +1,78 @@
from binance.um_futures import UMFutures
um_futures_client = UMFutures()
def get_binance_klines(symbol: str, interval: str, limit: int = 75):
"""
Fetch historical klines (candlestick data) from Binance.
:param symbol: The trading pair symbol (e.g., 'BTCUSDT').
:param interval: The time interval for the klines (e.g., '1m', '5m', '1h').
:param limit: The maximum number of klines to fetch (default is 75).
:return: A list of klines. [ timestamp, open, high, low, close, volume, ... ]
"""
return um_futures_client.klines(symbol=symbol, interval=interval, limit=limit)
def get_binance_depth(symbol: str, limit: int = 50):
"""
Fetch the order book depth from Binance.
:param symbol: The trading pair symbol (e.g., 'BTCUSDT').
:param limit: The maximum number of bids and asks to fetch (default is 50).
:return: A dictionary containing bids and asks. { "bids": [[price, quantity], ...], "asks": [[price, quantity], ...] }
"""
return um_futures_client.depth(symbol=symbol, limit=limit)
def get_binance_24hr_pricechange(symbol: str):
"""
Fetch 24-hour ticker price change statistics from Binance.
:param symbol: The trading pair symbol (e.g., 'BTCUSDT').
:return: A dictionary containing 24-hour statistics. { "priceChange": "...", "priceChangePercent": "...", "weightedAvgPrice": "...", ... }
"""
return um_futures_client.ticker_24hr_price_change(symbol=symbol)
def get_binance_toplongshort_position_ratio(symbol: str, period: str, limit: int = 50):
"""
Fetch the top long/short position ratio from Binance.
:param symbol: The trading pair symbol (e.g., 'BTCUSDT').
:param period: The time interval for the data (e.g., '1m', '5m', '1h').
:param limit: The maximum number of records to fetch (default is 50).
:return: A list of position ratios. [ { timestamp, longShortRatio, ... } ... ]
"""
return um_futures_client.top_long_short_position_ratio(symbol=symbol, period=period, limit=limit)
def get_binance_toplongshort_account_ratio(symbol: str, period: str, limit: int = 50):
"""
Fetch the top long/short account ratio from Binance.
:param symbol: The trading pair symbol (e.g., 'BTCUSDT').
:param period: The time interval for the data (e.g., '1m', '5m', '1h').
:param limit: The maximum number of records to fetch (default is 50).
:return: A list of account ratios. [ { timestamp, longShortRatio, ... } ... ]
"""
return um_futures_client.top_long_short_account_ratio(symbol=symbol, period=period, limit=limit)
def get_binance_global_longshort_account_ratio(symbol: str, period: str, limit: int = 50):
"""
Fetch the global long/short account ratio from Binance.
:param symbol: The trading pair symbol (e.g., 'BTCUSDT').
:param period: The time interval for the data (e.g., '1m', '5m', '1h').
:param limit: The maximum number of records to fetch (default is 50).
:return: A list of global account ratios. [ { timestamp, longShortRatio, ... } ... ]
"""
return um_futures_client.long_short_account_ratio(symbol=symbol, period=period, limit=limit)
def get_binance_taker_longshort_ratio(symbol: str, period: str, limit: int = 50):
"""
Fetch the taker long/short ratio from Binance.
:param symbol: The trading pair symbol (e.g., 'BTCUSDT').
:param period: The time interval for the data (e.g., '1m', '5m', '1h').
:param limit: The maximum number of records to fetch (default is 50).
:return: A list of taker ratios. [ { timestamp, buySellRatio, buyVol, sellVol, ... } ... ]
"""
return um_futures_client.taker_long_short_ratio(symbol=symbol, period=period, limit=limit)

View File

@ -5,6 +5,7 @@ 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 dateutil.relativedelta import relativedelta
from concurrent.futures import ThreadPoolExecutor
@ -466,6 +467,105 @@ def get_reddit_company_news(
return f"##{ticker} News Reddit, from {before} to {curr_date}:\n\n{news_str}"
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'"],
klines_limit: Annotated[int, "maximum number of klines to fetch, default is 75"] = 75,
depth_limit: Annotated[int, "maximum number of bids and asks to fetch, default is 50"] = 50,
longshort_limit: Annotated[int, "maximum number of long/short ratios to fetch, default is 50"] = 50,
) -> str:
"""
Fetch historical futures 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 klines (e.g., '1m', '5m', '1h').
klines_limit (int): The maximum number of klines to fetch (default is 75).
depth_limit (int): The maximum number of bids and asks to fetch (default is 50).
longshort_limit (int): The maximum number of long/short ratios to fetch (default is 50).
Returns:
str: A formatted string containing the historical futures data.
"""
symbol = symbol.upper().strip()
if not symbol.endswith("USDT"):
symbol += "USDT" # Ensure the symbol ends with USDT for futures
klines_str = ""
klines = get_binance_klines(symbol, interval, klines_limit)
if klines is not None and len(klines) != 0:
klines = list(map(lambda x: { "t": x[0], "o": x[1], "h": x[2], "l": x[3], "c": x[4], "v": x[5] }, klines))
klines_str = f"## {symbol} Futures **KLines Data** for {interval} interval:\n" + "\n".join(
[f"{entry["t"]}: Open: {entry["o"]}, High: {entry["h"]}, Low: {entry["l"]}, Close: {entry["c"]}, Volume: {entry["v"]}" for entry in klines]
) + "\n\n"
depth_str = ""
depth = get_binance_depth(symbol, depth_limit)
if depth is not None and isinstance(depth, dict):
bids = depth.get("bids", [-1, -1])
asks = depth.get("asks", [-1, -1])
depth = { "bids": { "price": bids[0], "volume": bids[1] }, "asks": { "price": asks[0], "volume": asks[1] } }
depth_str = f"## {symbol} Futures **Current Depth Data**:\nBids: Price: {depth["bids"]["price"]}, Volume: {depth["bids"]["volume"]}\nAsks: Price: {depth["asks"]["price"]}, Volume: {depth["asks"]["volume"]}\n\n"
ticker_24hr_str = ""
ticker_24hr = get_binance_24hr_pricechange(symbol)
if ticker_24hr is not None and isinstance(ticker_24hr, dict):
ticker_24hr_str = f"## {symbol} Futures **24-Hour Price Change**:\nPrice Change: {ticker_24hr.get("priceChange", "N/A")}, Price Change Percent: {ticker_24hr.get("priceChangePercent", "N/A")}, Weighted Avg Price: {ticker_24hr.get("weightedAvgPrice", "N/A")}\n\n"
top_longshort_position_ratio_str = ""
top_longshort_position_ratio = get_binance_toplongshort_position_ratio(symbol, interval, longshort_limit)
if top_longshort_position_ratio is not None and isinstance(top_longshort_position_ratio, list):
top_longshort_position_ratio = [
{ "t": entry["timestamp"], "longShortRatio": entry["longShortRatio"] }
for entry in top_longshort_position_ratio
]
top_longshort_position_ratio_str = f"## {symbol} Futures **Top Long/Short Position Ratio**:\n" + "\n".join(
[f"{entry["t"]}: Long/Short Ratio: {entry["longShortRatio"]}" for entry in top_longshort_position_ratio]
) + "\n\n"
top_longshort_account_ratio_str = ""
top_longshort_account_ratio = get_binance_toplongshort_account_ratio(symbol, interval, longshort_limit)
if top_longshort_account_ratio is not None and isinstance(top_longshort_account_ratio, list):
top_longshort_account_ratio = [
{ "t": entry["timestamp"], "longShortRatio": entry["longShortRatio"] }
for entry in top_longshort_account_ratio
]
top_longshort_account_ratio_str = f"## {symbol} Futures **Top Long/Short Account Ratio**:\n" + "\n".join(
[f"{entry["t"]}: Long/Short Ratio: {entry["longShortRatio"]}" for entry in top_longshort_account_ratio]
) + "\n\n"
global_longshort_account_ratio_str = ""
global_longshort_account_ratio = get_binance_global_longshort_account_ratio(symbol, interval, longshort_limit)
if global_longshort_account_ratio is not None and isinstance(global_longshort_account_ratio, list):
global_longshort_account_ratio = [
{ "t": entry["timestamp"], "longShortRatio": entry["longShortRatio"] }
for entry in global_longshort_account_ratio
]
global_longshort_account_ratio_str = f"## {symbol} Futures **Global Long/Short Account Ratio**:\n" + "\n".join(
[f"{entry["t"]}: Long/Short Ratio: {entry["longShortRatio"]}" for entry in global_longshort_account_ratio]
) + "\n\n"
taker_longshort_ratio_str = ""
taker_longshort_ratio = get_binance_taker_longshort_ratio(symbol, interval, longshort_limit)
if taker_longshort_ratio is not None and isinstance(taker_longshort_ratio, list):
taker_longshort_ratio = [
{ "t": entry["timestamp"], "buySellRatio": entry["buySellRatio"], "buyVol": entry["buyVol"], "sellVol": entry["sellVol"] }
for entry in taker_longshort_ratio
]
taker_longshort_ratio_str = f"## {symbol} Futures **Taker Long/Short Ratio**:\n" + "\n".join(
[f"{entry["t"]}: Long/Short Ratio: {entry["buySellRatio"]}, Buy Volume: {entry["buyVol"]}, Sell Volume: {entry["sellVol"]}" for entry in taker_longshort_ratio]
) + "\n\n"
return (
f"## {symbol} Futures Data:\n\n"
+ klines_str
+ depth_str
+ ticker_24hr_str
+ top_longshort_position_ratio_str
+ top_longshort_account_ratio_str
+ global_longshort_account_ratio_str
+ taker_longshort_ratio_str
)
def get_stock_stats_indicators_window(
symbol: Annotated[str, "ticker symbol of the company"],

View File

@ -118,7 +118,7 @@ class TradingAgentsGraph:
"market": ToolNode(
[
# online tools
self.toolkit.get_YFin_data_online,
self.toolkit.get_binance_data,
self.toolkit.get_stockstats_indicators_report_online,
# offline tools
self.toolkit.get_YFin_data,
@ -138,6 +138,8 @@ class TradingAgentsGraph:
# online tools
self.toolkit.get_global_news_openai,
self.toolkit.get_google_news,
self.toolkit.get_blockbeats_news,
self.toolkit.get_coindesk_news,
# offline tools
self.toolkit.get_finnhub_news,
self.toolkit.get_reddit_news,

View File

@ -47,7 +47,7 @@ Volatility Indicators:
Volume-Based Indicators:
- vwma: VWMA: A moving average weighted by volume. Usage: Confirm trends by integrating price action with volume data. Tips: Watch for skewed results from volume spikes; use in combination with other volume analyses.
- Select indicators that provide diverse and complementary information. Avoid redundancy (e.g., do not select both rsi and stochrsi). Also briefly explain why they are suitable for the given market context. When you tool call, please use the exact name of the indicators provided above as they are defined parameters, otherwise your call will fail. Please make sure to call get_YFin_data first to retrieve the CSV that is needed to generate indicators. Write a very detailed and nuanced report of the trends you observe. Do not simply state the trends are mixed, provide detailed and finegrained analysis and insights that may help traders make decisions.""" +
Select indicators that provide diverse and complementary information. Avoid redundancy (e.g., do not select both rsi and stochrsi). Also briefly explain why they are suitable for the given market context. Please make sure to call get_binance_data first to retrieve the CSV that is needed to generate indicators. Write a very detailed and nuanced report of the trends you observe. Do not simply state the trends are mixed, provide detailed and finegrained analysis and insights that may help traders make decisions.""" +
" Make sure to append a Markdown table at the end of the report to organize key points in the report, organized and easy to read."
)
},

View File

@ -2,10 +2,10 @@
PROMPTS = {
"analysts": {
"template": """你是一个高效的 AI 助理分析师,将与其他助理协同工作。请使用提供的工具尽可能推进问题的解决。若你无法完全解答也没关系,其他拥有不同工具的助理会接力完成。请尽你所能完成当前任务。
若你或其他助理得出了最终的投资建议买入/持有/卖出或完成了交付内容请在回复前加上前缀最终投资建议BUY/HOLD/SELL以提示团队停止操作
若你或其他助理得出了最终的投资建议买入/持有/卖出或完成了交付内容请在回复前加上前缀最终投资建议BUY/HOLD/SELL以提示团队停止操作虽然一下包含部分英文提示词但在输出时**务必使用中文**
你可以使用以下工具{tool_names}
{system_message}
当前日期{current_date}目标公司{ticker}""",
当前日期{current_date}目标资产{ticker}""",
#region Fundamentals Analyst
"fundamentals_analyst": {
@ -21,29 +21,30 @@ PROMPTS = {
"system_message": (
"""你是一名交易助理,负责分析金融市场走势。你的任务是从以下指标列表中,选出与当前市场环境或交易策略最相关的最多 8 个指标。你的目标是选择信息互补、避免重复的指标组合。指标分类及说明:
Moving Averages:
- close_50_sma: 50 SMA: A medium-term trend indicator. Usage: Identify trend direction and serve as dynamic support/resistance. Tips: It lags price; combine with faster indicators for timely signals.
- close_200_sma: 200 SMA: A long-term trend benchmark. Usage: Confirm overall market trend and identify golden/death cross setups. Tips: It reacts slowly; best for strategic trend confirmation rather than frequent trading entries.
- close_10_ema: 10 EMA: A responsive short-term average. Usage: Capture quick shifts in momentum and potential entry points. Tips: Prone to noise in choppy markets; use alongside longer averages for filtering false signals.
移动平均指标:
- close_50_sma: 50日简单移动平均线50 SMA中期趋势指标用途识别趋势方向并作为动态支撑/阻力位提示其响应滞后建议与更快的指标结合使用以获取及时信号
- close_200_sma: 200日简单移动平均线200 SMA长期趋势基准指标用途确认整体市场趋势识别黄金交叉/死亡交叉形态提示反应较慢更适用于战略性趋势确认而非频繁交易入场
- close_10_ema: 10日指数移动平均线10 EMA对价格变化反应迅速的短期平均用途捕捉动量变化和潜在进出场点提示在震荡行情中容易受到噪声干扰建议与较长周期均线结合使用以过滤虚假信号
MACD Related:
- macd: MACD: Computes momentum via differences of EMAs. Usage: Look for crossovers and divergence as signals of trend changes. Tips: Confirm with other indicators in low-volatility or sideways markets.
- macds: MACD Signal: An EMA smoothing of the MACD line. Usage: Use crossovers with the MACD line to trigger trades. Tips: Should be part of a broader strategy to avoid false positives.
- macdh: MACD Histogram: Shows the gap between the MACD line and its signal. Usage: Visualize momentum strength and spot divergence early. Tips: Can be volatile; complement with additional filters in fast-moving markets.
MACD 相关指标:
- macd: MACD通过EMA之间的差值计算动量用途观察交叉与背离作为趋势变化的信号提示在低波动或震荡市场中应结合其他指标确认信号有效性
- macds: MACD信号线MACD SignalMACD线的平滑EMA用途与MACD线交叉时提供交易触发信号提示建议作为策略组合的一部分使用以避免产生误判
- macdh: MACD柱状图MACD Histogram展示MACD线与信号线之间的差距用途可视化动量强度并早期识别背离提示可能较为剧烈波动建议在快节奏市场中搭配过滤器使用
Momentum Indicators:
- rsi: RSI: Measures momentum to flag overbought/oversold conditions. Usage: Apply 70/30 thresholds and watch for divergence to signal reversals. Tips: In strong trends, RSI may remain extreme; always cross-check with trend analysis.
动量指标:
- rsi: 相对强弱指标RSI衡量动量用于识别超买/超卖状态用途应用70/30阈值并关注背离信号以判断反转可能提示在强趋势中RSI可能长时间处于极端值需结合趋势分析确认信号
Volatility Indicators:
- boll: Bollinger Middle: A 20 SMA serving as the basis for Bollinger Bands. Usage: Acts as a dynamic benchmark for price movement. Tips: Combine with the upper and lower bands to effectively spot breakouts or reversals.
- boll_ub: Bollinger Upper Band: Typically 2 standard deviations above the middle line. Usage: Signals potential overbought conditions and breakout zones. Tips: Confirm signals with other tools; prices may ride the band in strong trends.
- boll_lb: Bollinger Lower Band: Typically 2 standard deviations below the middle line. Usage: Indicates potential oversold conditions. Tips: Use additional analysis to avoid false reversal signals.
- atr: ATR: Averages true range to measure volatility. Usage: Set stop-loss levels and adjust position sizes based on current market volatility. Tips: It's a reactive measure, so use it as part of a broader risk management strategy.
波动性指标:
- boll: 布林中轨Bollinger Middle以20日SMA为基础的布林带中线用途作为价格波动的动态基准提示结合上下轨使用更能有效识别突破或反转
- boll_ub: 布林上轨Bollinger Upper Band一般为中轨上方两个标准差用途提示可能处于超买状态或突破区域提示需结合其他工具确认信号强趋势中价格可能沿带运行
- boll_lb: 布林下轨Bollinger Lower Band一般为中轨下方两个标准差用途提示可能的超卖状态提示为避免错误信号应结合其他分析工具
- atr: 平均真实波幅ATR通过真实区间平均衡量市场波动用途设定止损水平并根据当前波动性调整仓位大小提示属于滞后型指标适合用于整体风险管理策略中
Volume-Based Indicators:
- vwma: VWMA: A moving average weighted by volume. Usage: Confirm trends by integrating price action with volume data. Tips: Watch for skewed results from volume spikes; use in combination with other volume analyses.
成交量指标:
- vwma: 成交量加权移动平均线VWMA基于成交量加权的价格平均用途将价格走势与成交量结合确认趋势强度提示成交量激增时可能造成偏差建议搭配其他成交量指标使用
选择提供多样化和互补信息的指标避免冗余例如不要同时选择rsi和stochrsi还简要解释为什么它们适合给定的市场环境当您调用工具时请使用上面提供的指标的确切名称因为它们是定义的参数否则您的调用将失败请确保首先调用 get_YFin_data 以检索生成指标所需的CSV写一份非常详细和细致入微的报告说明你观察到的趋势不要简单地说趋势是混合的提供详细和细粒度的分析和见解以帮助交易者做出决策""" +
选择提供多样化和互补信息的指标避免冗余例如不要同时选择rsi和stochrsi还简要解释为什么它们适合给定的市场环境请调用 get_binance_data 以获取资产的 K 线深度24 小时价格变化多空比等数据为了获取中短期的数据传入 interval 参数时请保证其范围为5m至1d之间此外必须分析15m和1h的趋势
写一份非常详细和细致入微的报告说明你观察到的趋势不要简单地说趋势是混合的提供详细和细粒度的分析和见解以帮助交易者做出决策""" +
" 最后请附上一张 Markdown 表格,总结并清晰地整理报告中的关键要点,便于阅读和参考。"
)
},