update
This commit is contained in:
parent
75ad00770d
commit
64c5ce606e
@ -84,7 +84,7 @@ class CryptoAgent:
|
||||
})
|
||||
|
||||
logger.info(f"加密货币智能体初始化完成(LLM 驱动),监控交易对: {self.symbols}")
|
||||
logger.info(f"模拟交易: 始终启用")
|
||||
logger.info(f"📊 交易: 始终启用")
|
||||
|
||||
if self.real_trading:
|
||||
auto_status = "启用" if self.real_trading.get_auto_trading_status() else "禁用"
|
||||
@ -977,7 +977,7 @@ class CryptoAgent:
|
||||
decision_text = decision_map.get(decision_type, decision_type)
|
||||
|
||||
# 账户类型标识
|
||||
account_type = "📊 模拟" if is_paper else "💰 实盘"
|
||||
account_type = "📊" if is_paper else "💰"
|
||||
|
||||
# 方向图标
|
||||
if 'long' in action.lower() or 'buy' in action.lower():
|
||||
@ -1484,7 +1484,7 @@ class CryptoAgent:
|
||||
"""发送有信号但未执行交易的通知"""
|
||||
try:
|
||||
symbol = market_signal.get('symbol')
|
||||
account_type = "📊 模拟" if is_paper else "💰 实盘"
|
||||
account_type = "📊" if is_paper else "💰"
|
||||
|
||||
# 获取最佳信号
|
||||
best_signal = self._get_best_signal_from_market(market_signal)
|
||||
|
||||
@ -54,18 +54,32 @@ async def price_monitor_loop():
|
||||
side_icon = "🟢" if result.get('side') == 'long' else "🔴"
|
||||
grade = result.get('signal_grade', 'N/A')
|
||||
|
||||
title = f"✅ 挂单成交 - {result.get('symbol')}"
|
||||
symbol = result.get('symbol', '')
|
||||
entry_price = result.get('entry_price', 0)
|
||||
filled_price = result.get('filled_price', 0)
|
||||
stop_loss = result.get('stop_loss', 0)
|
||||
take_profit = result.get('take_profit', 0)
|
||||
|
||||
# 根据交易对精度格式化价格
|
||||
try:
|
||||
from app.services.bitget_service import bitget_service
|
||||
precision = bitget_service.get_precision(symbol)
|
||||
price_fmt = f"{{:,.{precision['pricePrecision']}f}}"
|
||||
except:
|
||||
price_fmt = "{:,.2f}"
|
||||
|
||||
title = f"✅ 挂单成交 - {symbol}"
|
||||
content_parts = [
|
||||
f"{side_icon} **方向**: {side_text}",
|
||||
f"⭐ **信号等级**: {grade}",
|
||||
f"💰 **挂单价**: ${result.get('entry_price', 0):,.2f}",
|
||||
f"🎯 **成交价**: ${result.get('filled_price', 0):,.2f}",
|
||||
f"💰 **挂单价**: ${price_fmt.format(entry_price)}",
|
||||
f"🎯 **成交价**: ${price_fmt.format(filled_price)}",
|
||||
f"💵 **仓位**: ${result.get('quantity', 0):,.0f}",
|
||||
]
|
||||
if result.get('stop_loss'):
|
||||
content_parts.append(f"🛑 **止损**: ${result.get('stop_loss', 0):,.2f}")
|
||||
if result.get('take_profit'):
|
||||
content_parts.append(f"🎯 **止盈**: ${result.get('take_profit', 0):,.2f}")
|
||||
if stop_loss:
|
||||
content_parts.append(f"🛑 **止损**: ${price_fmt.format(stop_loss)}")
|
||||
if take_profit:
|
||||
content_parts.append(f"🎯 **止盈**: ${price_fmt.format(take_profit)}")
|
||||
|
||||
content = "\n".join(content_parts)
|
||||
|
||||
@ -152,6 +166,15 @@ async def price_monitor_loop():
|
||||
side_icon = '🟢' if result.get('side') == 'long' else '🔴'
|
||||
pnl = result.get('current_pnl_percent', 0)
|
||||
symbol_display = result.get('symbol', '')
|
||||
new_stop_loss = result.get('new_stop_loss', 0)
|
||||
|
||||
# 根据交易对精度格式化价格
|
||||
try:
|
||||
from app.services.bitget_service import bitget_service
|
||||
precision = bitget_service.get_precision(symbol_display)
|
||||
price_fmt = f"{{:,.{precision['pricePrecision']}f}}"
|
||||
except:
|
||||
price_fmt = "{:,.2f}"
|
||||
|
||||
if move_type == 'trailing_first':
|
||||
title = f"📈 移动止损已激活 - {symbol_display}"
|
||||
@ -159,7 +182,7 @@ async def price_monitor_loop():
|
||||
f"{side_icon} **方向**: {side_text}",
|
||||
f"",
|
||||
f"📈 **当前盈利**: {pnl:+.2f}%",
|
||||
f"🛑 **新止损价**: ${result.get('new_stop_loss', 0):,.2f}",
|
||||
f"🛑 **新止损价**: ${price_fmt.format(new_stop_loss)}",
|
||||
f"",
|
||||
f"💰 锁定利润,让利润奔跑"
|
||||
]
|
||||
@ -170,7 +193,7 @@ async def price_monitor_loop():
|
||||
f"{side_icon} **方向**: {side_text}",
|
||||
f"",
|
||||
f"📈 **当前盈利**: {pnl:+.2f}%",
|
||||
f"🛑 **新止损价**: ${result.get('new_stop_loss', 0):,.2f}",
|
||||
f"🛑 **新止损价**: ${price_fmt.format(new_stop_loss)}",
|
||||
f"",
|
||||
f"🎯 继续锁定更多利润"
|
||||
]
|
||||
@ -181,7 +204,7 @@ async def price_monitor_loop():
|
||||
f"{side_icon} **方向**: {side_text}",
|
||||
f"",
|
||||
f"📈 **当前盈利**: {pnl:+.2f}%",
|
||||
f"🛑 **新止损价**: ${result.get('new_stop_loss', 0):,.2f}",
|
||||
f"🛑 **新止损价**: ${price_fmt.format(new_stop_loss)}",
|
||||
f"",
|
||||
f"💰 锁定利润,让利润奔跑"
|
||||
]
|
||||
@ -205,19 +228,33 @@ async def price_monitor_loop():
|
||||
side_icon = '🟢' if result.get('side') == 'long' else '🔴'
|
||||
grade = result.get('signal_grade', 'N/A')
|
||||
|
||||
title = f"✅ 挂单成交 - {result.get('symbol')}"
|
||||
symbol = result.get('symbol', '')
|
||||
entry_price = result.get('entry_price', 0)
|
||||
filled_price = result.get('filled_price', 0)
|
||||
stop_loss = result.get('stop_loss', 0)
|
||||
take_profit = result.get('take_profit', 0)
|
||||
|
||||
# 根据交易对精度格式化价格
|
||||
try:
|
||||
from app.services.bitget_service import bitget_service
|
||||
precision = bitget_service.get_precision(symbol)
|
||||
price_fmt = f"{{:,.{precision['pricePrecision']}f}}"
|
||||
except:
|
||||
price_fmt = "{:,.2f}"
|
||||
|
||||
title = f"✅ 挂单成交 - {symbol}"
|
||||
|
||||
content_parts = [
|
||||
f"{side_icon} **方向**: {side_text}",
|
||||
f"",
|
||||
f"⭐ **信号等级**: {grade}",
|
||||
f"",
|
||||
f"💰 **挂单价**: ${result.get('entry_price', 0):,.2f}",
|
||||
f"🎯 **成交价**: ${result.get('filled_price', 0):,.2f}",
|
||||
f"💰 **挂单价**: ${price_fmt.format(entry_price)}",
|
||||
f"🎯 **成交价**: ${price_fmt.format(filled_price)}",
|
||||
f"📊 **持仓价值**: ${result.get('quantity', 0):,.0f}",
|
||||
f"",
|
||||
f"🛑 **止损价**: ${result.get('stop_loss', 0):,.2f}",
|
||||
f"🎯 **止盈价**: ${result.get('take_profit', 0):,.2f}"
|
||||
f"🛑 **止损价**: ${price_fmt.format(stop_loss)}",
|
||||
f"🎯 **止盈价**: ${price_fmt.format(take_profit)}"
|
||||
]
|
||||
|
||||
content = "\n".join(content_parts)
|
||||
|
||||
@ -370,6 +370,119 @@ class BitgetService:
|
||||
logger.error(f"获取 {symbol} ticker 失败: {e}")
|
||||
return None
|
||||
|
||||
def get_symbol_info(self, symbol: str, category: str = None) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
获取交易对信息(包含精度配置)
|
||||
|
||||
Args:
|
||||
symbol: 交易对
|
||||
category: 产品类型,默认 USDT-FUTURES
|
||||
|
||||
Returns:
|
||||
交易对信息,包含 pricePrecision 和 quantityPrecision
|
||||
"""
|
||||
try:
|
||||
if category is None:
|
||||
category = self.CATEGORY_USDT_FUTURES
|
||||
|
||||
url = f"{self._base_url}/api/v3/market/symbols"
|
||||
params = {
|
||||
'category': category,
|
||||
'symbol': symbol
|
||||
}
|
||||
|
||||
response = self._session.get(url, params=params, timeout=10)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
|
||||
if result.get('code') != '00000':
|
||||
logger.error(f"Bitget API 错误: {result.get('msg')}")
|
||||
return None
|
||||
|
||||
data = result.get('data', [])
|
||||
if not data:
|
||||
return None
|
||||
|
||||
symbol_data = data[0]
|
||||
|
||||
# 返回精度信息
|
||||
return {
|
||||
'symbol': symbol_data.get('symbol'),
|
||||
'status': symbol_data.get('status'),
|
||||
'pricePrecision': int(symbol_data.get('pricePrecision', 2)),
|
||||
'quantityPrecision': int(symbol_data.get('quantityPrecision', 2)),
|
||||
'minTradeAmount': float(symbol_data.get('minTradeAmount', 0)),
|
||||
'maxTradeAmount': float(symbol_data.get('maxTradeAmount', 0)),
|
||||
'takerFeeRate': float(symbol_data.get('takerFeeRate', 0.001)),
|
||||
'makerFeeRate': float(symbol_data.get('makerFeeRate', 0.001)),
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取 {symbol} 交易对信息失败: {e}")
|
||||
return None
|
||||
|
||||
# 缓存交易对精度信息
|
||||
_symbol_precision_cache: Dict[str, Dict[str, int]] = {}
|
||||
|
||||
def get_precision(self, symbol: str, category: str = None) -> Dict[str, int]:
|
||||
"""
|
||||
获取交易对价格和数量精度(带缓存)
|
||||
|
||||
Args:
|
||||
symbol: 交易对
|
||||
category: 产品类型,默认 USDT-FUTURES
|
||||
|
||||
Returns:
|
||||
{'pricePrecision': 2, 'quantityPrecision': 2}
|
||||
"""
|
||||
# 检查缓存
|
||||
if symbol in self._symbol_precision_cache:
|
||||
return self._symbol_precision_cache[symbol]
|
||||
|
||||
# 获取交易对信息
|
||||
info = self.get_symbol_info(symbol, category)
|
||||
if info:
|
||||
precision = {
|
||||
'pricePrecision': info['pricePrecision'],
|
||||
'quantityPrecision': info['quantityPrecision']
|
||||
}
|
||||
# 缓存结果
|
||||
self._symbol_precision_cache[symbol] = precision
|
||||
return precision
|
||||
|
||||
# 默认精度
|
||||
return {'pricePrecision': 2, 'quantityPrecision': 2}
|
||||
|
||||
def round_price(self, symbol: str, price: float, category: str = None) -> float:
|
||||
"""
|
||||
根据交易对精度四舍五入价格
|
||||
|
||||
Args:
|
||||
symbol: 交易对
|
||||
price: 原始价格
|
||||
category: 产品类型
|
||||
|
||||
Returns:
|
||||
四舍五入后的价格
|
||||
"""
|
||||
precision = self.get_precision(symbol, category)
|
||||
return round(price, precision['pricePrecision'])
|
||||
|
||||
def round_quantity(self, symbol: str, quantity: float, category: str = None) -> float:
|
||||
"""
|
||||
根据交易对精度四舍五入数量
|
||||
|
||||
Args:
|
||||
symbol: 交易对
|
||||
quantity: 原始数量
|
||||
category: 产品类型
|
||||
|
||||
Returns:
|
||||
四舍五入后的数量
|
||||
"""
|
||||
precision = self.get_precision(symbol, category)
|
||||
return round(quantity, precision['quantityPrecision'])
|
||||
|
||||
def get_funding_rate(self, symbol: str) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
获取资金费率(包含标记价格和指数价格)
|
||||
|
||||
@ -116,6 +116,26 @@ class PaperTradingService:
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
def _apply_price_precision(self, symbol: str, price: float) -> float:
|
||||
"""
|
||||
应用交易对价格精度
|
||||
|
||||
Args:
|
||||
symbol: 交易对
|
||||
price: 原始价格
|
||||
|
||||
Returns:
|
||||
四舍五入后的价格
|
||||
"""
|
||||
if price is None or price == 0:
|
||||
return price
|
||||
try:
|
||||
from app.services.bitget_service import bitget_service
|
||||
return bitget_service.round_price(symbol, price)
|
||||
except Exception as e:
|
||||
logger.debug(f"价格精度调整失败 {symbol}: {e},使用原始价格")
|
||||
return price
|
||||
|
||||
def create_order_from_signal(self, signal: Dict[str, Any], current_price: float = None) -> Dict[str, Any]:
|
||||
"""
|
||||
从交易信号创建模拟订单
|
||||
|
||||
Loading…
Reference in New Issue
Block a user