增加合约市场
This commit is contained in:
parent
75592857a3
commit
5173c05e65
@ -426,7 +426,9 @@ class LLMSignalAnalyzer:
|
||||
agent_type: 智能体类型,支持 'crypto', 'stock', 'smart'
|
||||
"""
|
||||
from app.config import get_settings
|
||||
from app.services.binance_service import binance_service
|
||||
self.news_service = get_news_service()
|
||||
self.binance_service = binance_service
|
||||
settings = get_settings()
|
||||
|
||||
# 根据智能体类型选择模型配置
|
||||
@ -482,6 +484,17 @@ class LLMSignalAnalyzer:
|
||||
# 获取新闻数据
|
||||
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':
|
||||
system_prompt = self.STOCK_SYSTEM_PROMPT
|
||||
@ -489,7 +502,7 @@ class LLMSignalAnalyzer:
|
||||
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
|
||||
response = llm_service.chat([
|
||||
@ -595,7 +608,8 @@ class LLMSignalAnalyzer:
|
||||
return "\n".join(lines)
|
||||
|
||||
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.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'])
|
||||
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:
|
||||
parts.append("\n## 账户与持仓状态")
|
||||
|
||||
@ -22,6 +22,7 @@ class BinanceService:
|
||||
|
||||
# Binance API 基础 URL
|
||||
BASE_URL = "https://api.binance.com"
|
||||
FUTURES_URL = "https://fapi.binance.com" # 合约 API
|
||||
|
||||
def __init__(self, api_key: str = "", api_secret: str = ""):
|
||||
"""
|
||||
@ -272,6 +273,233 @@ class BinanceService:
|
||||
logger.error(f"获取 {symbol} 24h 统计失败: {e}")
|
||||
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()
|
||||
|
||||
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