增加合约市场
This commit is contained in:
parent
75592857a3
commit
5173c05e65
@ -426,7 +426,9 @@ class LLMSignalAnalyzer:
|
|||||||
agent_type: 智能体类型,支持 'crypto', 'stock', 'smart'
|
agent_type: 智能体类型,支持 'crypto', 'stock', 'smart'
|
||||||
"""
|
"""
|
||||||
from app.config import get_settings
|
from app.config import get_settings
|
||||||
|
from app.services.binance_service import binance_service
|
||||||
self.news_service = get_news_service()
|
self.news_service = get_news_service()
|
||||||
|
self.binance_service = binance_service
|
||||||
settings = get_settings()
|
settings = get_settings()
|
||||||
|
|
||||||
# 根据智能体类型选择模型配置
|
# 根据智能体类型选择模型配置
|
||||||
@ -482,6 +484,17 @@ class LLMSignalAnalyzer:
|
|||||||
# 获取新闻数据
|
# 获取新闻数据
|
||||||
news_text = await self._get_news_context(symbol, symbols or [symbol])
|
news_text = await self._get_news_context(symbol, symbols or [symbol])
|
||||||
|
|
||||||
|
# 获取合约市场数据(仅加密货币)
|
||||||
|
futures_data = None
|
||||||
|
if self.agent_type == 'crypto':
|
||||||
|
try:
|
||||||
|
futures_data = self.binance_service.get_futures_market_data(symbol)
|
||||||
|
if futures_data:
|
||||||
|
logger.info(f"{symbol} 资金费率: {futures_data.get('funding_rate', {}).get('funding_rate_percent', 0):.4f}% | "
|
||||||
|
f"情绪: {futures_data.get('market_sentiment', '')}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"获取 {symbol} 合约数据失败: {e}")
|
||||||
|
|
||||||
# 根据智能体类型选择提示词
|
# 根据智能体类型选择提示词
|
||||||
if self.agent_type == 'stock':
|
if self.agent_type == 'stock':
|
||||||
system_prompt = self.STOCK_SYSTEM_PROMPT
|
system_prompt = self.STOCK_SYSTEM_PROMPT
|
||||||
@ -489,7 +502,7 @@ class LLMSignalAnalyzer:
|
|||||||
system_prompt = self.CRYPTO_SYSTEM_PROMPT
|
system_prompt = self.CRYPTO_SYSTEM_PROMPT
|
||||||
|
|
||||||
# 构建数据提示
|
# 构建数据提示
|
||||||
data_prompt = self._build_data_prompt(symbol, data, news_text, position_info)
|
data_prompt = self._build_data_prompt(symbol, data, news_text, position_info, futures_data)
|
||||||
|
|
||||||
# 调用 LLM
|
# 调用 LLM
|
||||||
response = llm_service.chat([
|
response = llm_service.chat([
|
||||||
@ -595,7 +608,8 @@ class LLMSignalAnalyzer:
|
|||||||
return "\n".join(lines)
|
return "\n".join(lines)
|
||||||
|
|
||||||
def _build_data_prompt(self, symbol: str, data: Dict[str, pd.DataFrame],
|
def _build_data_prompt(self, symbol: str, data: Dict[str, pd.DataFrame],
|
||||||
news_text: str = "", position_info: Dict[str, Any] = None) -> str:
|
news_text: str = "", position_info: Dict[str, Any] = None,
|
||||||
|
futures_data: Dict[str, Any] = None) -> str:
|
||||||
"""构建数据提示词"""
|
"""构建数据提示词"""
|
||||||
parts = [f"# {symbol} 市场数据分析\n"]
|
parts = [f"# {symbol} 市场数据分析\n"]
|
||||||
parts.append(f"分析时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
|
parts.append(f"分析时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
|
||||||
@ -606,6 +620,10 @@ class LLMSignalAnalyzer:
|
|||||||
current_price = float(data['5m'].iloc[-1]['close'])
|
current_price = float(data['5m'].iloc[-1]['close'])
|
||||||
parts.append(f"**当前价格**: ${current_price:,.2f}\n")
|
parts.append(f"**当前价格**: ${current_price:,.2f}\n")
|
||||||
|
|
||||||
|
# === 新增:合约市场数据 ===
|
||||||
|
if futures_data and self.agent_type == 'crypto':
|
||||||
|
parts.append(self.binance_service.format_futures_data_for_llm(symbol, futures_data))
|
||||||
|
|
||||||
# === 新增:账户和持仓信息 ===
|
# === 新增:账户和持仓信息 ===
|
||||||
if position_info:
|
if position_info:
|
||||||
parts.append("\n## 账户与持仓状态")
|
parts.append("\n## 账户与持仓状态")
|
||||||
|
|||||||
@ -22,6 +22,7 @@ class BinanceService:
|
|||||||
|
|
||||||
# Binance API 基础 URL
|
# Binance API 基础 URL
|
||||||
BASE_URL = "https://api.binance.com"
|
BASE_URL = "https://api.binance.com"
|
||||||
|
FUTURES_URL = "https://fapi.binance.com" # 合约 API
|
||||||
|
|
||||||
def __init__(self, api_key: str = "", api_secret: str = ""):
|
def __init__(self, api_key: str = "", api_secret: str = ""):
|
||||||
"""
|
"""
|
||||||
@ -272,6 +273,233 @@ class BinanceService:
|
|||||||
logger.error(f"获取 {symbol} 24h 统计失败: {e}")
|
logger.error(f"获取 {symbol} 24h 统计失败: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def get_funding_rate(self, symbol: str) -> Optional[Dict[str, Any]]:
|
||||||
|
"""
|
||||||
|
获取资金费率
|
||||||
|
|
||||||
|
Args:
|
||||||
|
symbol: 交易对,如 'BTCUSDT'
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
包含资金费率信息的字典
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
url = f"{self.FUTURES_URL}/fapi/v1/premiumIndex"
|
||||||
|
params = {'symbol': symbol}
|
||||||
|
response = self._session.get(url, params=params, timeout=10)
|
||||||
|
response.raise_for_status()
|
||||||
|
data = response.json()
|
||||||
|
|
||||||
|
# 解析资金费率
|
||||||
|
funding_rate = float(data.get('lastFundingRate', 0))
|
||||||
|
mark_price = float(data.get('markPrice', 0))
|
||||||
|
index_price = float(data.get('indexPrice', 0))
|
||||||
|
next_funding_time = int(data.get('nextFundingTime', 0))
|
||||||
|
|
||||||
|
# 判断市场情绪
|
||||||
|
if funding_rate > 0.01: # > 0.1%
|
||||||
|
sentiment = "极度贪婪"
|
||||||
|
sentiment_level = "extreme_greed"
|
||||||
|
elif funding_rate > 0.05: # > 0.05%
|
||||||
|
sentiment = "贪婪"
|
||||||
|
sentiment_level = "greed"
|
||||||
|
elif funding_rate < -0.01: # < -0.1%
|
||||||
|
sentiment = "极度恐惧"
|
||||||
|
sentiment_level = "extreme_fear"
|
||||||
|
elif funding_rate < -0.05: # < -0.05%
|
||||||
|
sentiment = "恐惧"
|
||||||
|
sentiment_level = "fear"
|
||||||
|
else:
|
||||||
|
sentiment = "中性"
|
||||||
|
sentiment_level = "neutral"
|
||||||
|
|
||||||
|
return {
|
||||||
|
'funding_rate': funding_rate,
|
||||||
|
'funding_rate_percent': funding_rate * 100, # 转为百分比
|
||||||
|
'mark_price': mark_price,
|
||||||
|
'index_price': index_price,
|
||||||
|
'next_funding_time': next_funding_time,
|
||||||
|
'sentiment': sentiment,
|
||||||
|
'sentiment_level': sentiment_level
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"获取 {symbol} 资金费率失败: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_open_interest(self, symbol: str) -> Optional[Dict[str, Any]]:
|
||||||
|
"""
|
||||||
|
获取持仓量
|
||||||
|
|
||||||
|
Args:
|
||||||
|
symbol: 交易对,如 'BTCUSDT'
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
包含持仓量信息的字典
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
url = f"{self.FUTURES_URL}/fapi/v1/openInterest"
|
||||||
|
params = {'symbol': symbol}
|
||||||
|
response = self._session.get(url, params=params, timeout=10)
|
||||||
|
response.raise_for_status()
|
||||||
|
data = response.json()
|
||||||
|
|
||||||
|
open_interest = float(data.get('openInterest', 0))
|
||||||
|
open_interest_value = float(data.get('openInterestValue', 0))
|
||||||
|
|
||||||
|
return {
|
||||||
|
'open_interest': open_interest,
|
||||||
|
'open_interest_value': open_interest_value,
|
||||||
|
'timestamp': int(data.get('time', 0))
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"获取 {symbol} 持仓量失败: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_open_interest_hist(self, symbol: str, period: str = '5m',
|
||||||
|
limit: int = 30) -> Optional[List[Dict[str, Any]]]:
|
||||||
|
"""
|
||||||
|
获取历史持仓量(用于计算变化趋势)
|
||||||
|
|
||||||
|
Args:
|
||||||
|
symbol: 交易对
|
||||||
|
period: 周期 (5m, 15m, 30m, 1h, 2h, 4h, 6h, 12h, 1d)
|
||||||
|
limit: 获取数量 (最大 500)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
持仓量历史列表
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Binance 使用正确的 API 端点
|
||||||
|
url = f"{self.FUTURES_URL}/futures/data/openInterestHist"
|
||||||
|
params = {
|
||||||
|
'symbol': symbol,
|
||||||
|
'period': period,
|
||||||
|
'limit': limit
|
||||||
|
}
|
||||||
|
response = self._session.get(url, params=params, timeout=10)
|
||||||
|
response.raise_for_status()
|
||||||
|
data = response.json()
|
||||||
|
|
||||||
|
return data
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"获取 {symbol} 历史持仓量失败: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_futures_market_data(self, symbol: str) -> Optional[Dict[str, Any]]:
|
||||||
|
"""
|
||||||
|
获取合约市场综合数据(资金费率 + 持仓量 + 趋势分析)
|
||||||
|
|
||||||
|
Args:
|
||||||
|
symbol: 交易对
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
综合市场数据
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# 并发获取数据
|
||||||
|
funding_rate = self.get_funding_rate(symbol)
|
||||||
|
open_interest = self.get_open_interest(symbol)
|
||||||
|
|
||||||
|
if not funding_rate or not open_interest:
|
||||||
|
logger.warning(f"获取 {symbol} 合约数据不完整")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# 获取历史持仓量计算趋势
|
||||||
|
hist_oi = self.get_open_interest_hist(symbol, period='1h', limit=24)
|
||||||
|
oi_change = 0
|
||||||
|
oi_change_percent = 0
|
||||||
|
|
||||||
|
if hist_oi and len(hist_oi) >= 2:
|
||||||
|
oi_24h_ago = float(hist_oi[-1].get('sumOpenInterest', 0))
|
||||||
|
oi_now = float(hist_oi[0].get('sumOpenInterest', 0))
|
||||||
|
oi_change = oi_now - oi_24h_ago
|
||||||
|
oi_change_percent = (oi_change / oi_24h_ago * 100) if oi_24h_ago > 0 else 0
|
||||||
|
|
||||||
|
# 计算溢价率
|
||||||
|
premium_rate = 0
|
||||||
|
if funding_rate.get('index_price', 0) > 0:
|
||||||
|
premium_rate = ((funding_rate['mark_price'] - funding_rate['index_price'])
|
||||||
|
/ funding_rate['index_price'] * 100)
|
||||||
|
|
||||||
|
return {
|
||||||
|
'funding_rate': funding_rate,
|
||||||
|
'open_interest': open_interest,
|
||||||
|
'oi_change_24h': oi_change,
|
||||||
|
'oi_change_percent_24h': oi_change_percent,
|
||||||
|
'premium_rate': premium_rate,
|
||||||
|
'market_sentiment': funding_rate.get('sentiment', ''),
|
||||||
|
'sentiment_level': funding_rate.get('sentiment_level', '')
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"获取 {symbol} 合约市场数据失败: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def format_futures_data_for_llm(self, symbol: str,
|
||||||
|
market_data: Dict[str, Any]) -> str:
|
||||||
|
"""
|
||||||
|
格式化合约数据供 LLM 分析
|
||||||
|
|
||||||
|
Args:
|
||||||
|
symbol: 交易对
|
||||||
|
market_data: 合约市场数据
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
格式化的文本
|
||||||
|
"""
|
||||||
|
if not market_data:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
lines = [f"\n## {symbol} 合约市场数据\n"]
|
||||||
|
|
||||||
|
# 资金费率
|
||||||
|
funding = market_data.get('funding_rate', {})
|
||||||
|
if funding:
|
||||||
|
fr = funding.get('funding_rate_percent', 0)
|
||||||
|
sentiment = funding.get('sentiment', '')
|
||||||
|
lines.append(f"### 资金费率")
|
||||||
|
lines.append(f"• 当前费率: {fr:.4f}%")
|
||||||
|
lines.append(f"• 市场情绪: {sentiment}")
|
||||||
|
lines.append(f"• 标记价格: ${funding.get('mark_price', 0):,.2f}")
|
||||||
|
lines.append(f"• 指数价格: ${funding.get('index_price', 0):,.2f}")
|
||||||
|
|
||||||
|
# 资金费率分析
|
||||||
|
if fr > 0.1:
|
||||||
|
lines.append(f"• ⚠️ 极高费率,多头过度杠杆,警惕回调风险")
|
||||||
|
elif fr > 0.05:
|
||||||
|
lines.append(f"• 正费率,多头占优但未极端")
|
||||||
|
elif fr < -0.1:
|
||||||
|
lines.append(f"• ⚠️ 极低费率,空头过度杠杆,可能反弹")
|
||||||
|
elif fr < -0.05:
|
||||||
|
lines.append(f"• 负费率,空头占优但未极端")
|
||||||
|
|
||||||
|
# 持仓量
|
||||||
|
oi = market_data.get('open_interest', {})
|
||||||
|
if oi:
|
||||||
|
lines.append(f"\n### 持仓量")
|
||||||
|
lines.append(f"• 当前持仓: {oi.get('open_interest', 0):,.0f} 张")
|
||||||
|
lines.append(f"• 持仓金额: ${oi.get('open_interest_value', 0):,.0f}")
|
||||||
|
|
||||||
|
# 持仓量变化
|
||||||
|
oi_change = market_data.get('oi_change_percent_24h', 0)
|
||||||
|
if oi_change != 0:
|
||||||
|
lines.append(f"• 24h变化: {oi_change:+.2f}%")
|
||||||
|
if oi_change > 10:
|
||||||
|
lines.append(f"• ⚠️ 持仓大幅增加,资金加速流入")
|
||||||
|
elif oi_change < -10:
|
||||||
|
lines.append(f"• ⚠️ 持仓大幅减少,资金加速流出")
|
||||||
|
|
||||||
|
# 溢价率
|
||||||
|
premium = market_data.get('premium_rate', 0)
|
||||||
|
if premium != 0:
|
||||||
|
lines.append(f"\n### 溢价分析")
|
||||||
|
lines.append(f"• 现货溢价: {premium:+.2f}%")
|
||||||
|
if premium > 1:
|
||||||
|
lines.append(f"• ⚠️ 高溢价,市场过热")
|
||||||
|
elif premium < -1:
|
||||||
|
lines.append(f"• ⚠️ 负溢价,市场偏冷")
|
||||||
|
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
# 全局实例
|
# 全局实例
|
||||||
binance_service = BinanceService()
|
binance_service = BinanceService()
|
||||||
|
|||||||
80
scripts/test_futures_data.py
Executable file
80
scripts/test_futures_data.py
Executable file
@ -0,0 +1,80 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
测试合约市场数据获取
|
||||||
|
"""
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
# 确保路径正确
|
||||||
|
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
project_root = os.path.dirname(script_dir)
|
||||||
|
backend_dir = os.path.join(project_root, 'backend')
|
||||||
|
sys.path.insert(0, backend_dir)
|
||||||
|
|
||||||
|
from app.services.binance_service import binance_service
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("=" * 60)
|
||||||
|
print("📊 测试 Binance 合约市场数据获取")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
symbols = ['BTCUSDT', 'ETHUSDT']
|
||||||
|
|
||||||
|
for symbol in symbols:
|
||||||
|
print(f"\n{'='*60}")
|
||||||
|
print(f"📈 {symbol} 合约市场数据")
|
||||||
|
print(f"{'='*60}")
|
||||||
|
|
||||||
|
# 1. 获取资金费率
|
||||||
|
print(f"\n🔍 获取资金费率...")
|
||||||
|
funding_rate = binance_service.get_funding_rate(symbol)
|
||||||
|
if funding_rate:
|
||||||
|
print(f"✅ 资金费率: {funding_rate['funding_rate_percent']:.4f}%")
|
||||||
|
print(f" 市场情绪: {funding_rate['sentiment']}")
|
||||||
|
print(f" 标记价格: ${funding_rate['mark_price']:,.2f}")
|
||||||
|
print(f" 指数价格: ${funding_rate['index_price']:,.2f}")
|
||||||
|
|
||||||
|
# 2. 获取持仓量
|
||||||
|
print(f"\n🔍 获取持仓量...")
|
||||||
|
open_interest = binance_service.get_open_interest(symbol)
|
||||||
|
if open_interest:
|
||||||
|
print(f"✅ 持仓量: {open_interest['open_interest']:,.0f} 张")
|
||||||
|
print(f" 持仓金额: ${open_interest['open_interest_value']:,.0f}")
|
||||||
|
|
||||||
|
# 3. 获取历史持仓量
|
||||||
|
print(f"\n🔍 获取历史持仓量(计算24h变化)...")
|
||||||
|
hist_oi = binance_service.get_open_interest_hist(symbol, period='1h', limit=24)
|
||||||
|
if hist_oi and len(hist_oi) >= 2:
|
||||||
|
oi_now = float(hist_oi[0].get('sumOpenInterest', 0))
|
||||||
|
oi_24h = float(hist_oi[-1].get('sumOpenInterest', 0))
|
||||||
|
oi_change = oi_now - oi_24h
|
||||||
|
oi_change_pct = (oi_change / oi_24h * 100) if oi_24h > 0 else 0
|
||||||
|
print(f"✅ 24h前: {oi_24h:,.0f} 张")
|
||||||
|
print(f" 当前: {oi_now:,.0f} 张")
|
||||||
|
print(f" 变化: {oi_change:+,.0f} 张 ({oi_change_pct:+.2f}%)")
|
||||||
|
|
||||||
|
# 4. 获取综合数据
|
||||||
|
print(f"\n🔍 获取综合合约数据...")
|
||||||
|
market_data = binance_service.get_futures_market_data(symbol)
|
||||||
|
if market_data:
|
||||||
|
print(f"✅ 综合数据获取成功")
|
||||||
|
print(f" 资金费率: {market_data['funding_rate']['funding_rate_percent']:.4f}%")
|
||||||
|
print(f" 持仓24h变化: {market_data['oi_change_percent_24h']:+.2f}%")
|
||||||
|
print(f" 溢价率: {market_data['premium_rate']:+.2f}%")
|
||||||
|
print(f" 市场情绪: {market_data['market_sentiment']}")
|
||||||
|
|
||||||
|
# 5. 格式化给 LLM 的数据
|
||||||
|
print(f"\n🤖 格式化给 LLM 的数据:")
|
||||||
|
print(f"{'─'*60}")
|
||||||
|
if market_data:
|
||||||
|
formatted = binance_service.format_futures_data_for_llm(symbol, market_data)
|
||||||
|
print(formatted)
|
||||||
|
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print("✅ 测试完成")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Loading…
Reference in New Issue
Block a user