update
This commit is contained in:
parent
020b0f4eb3
commit
b26f7713b4
@ -1488,6 +1488,7 @@ class CryptoAgent:
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
symbol = decision.get('symbol')
|
symbol = decision.get('symbol')
|
||||||
|
decision_action = decision.get('action', '') # buy/sell
|
||||||
orders_to_cancel = decision.get('orders_to_cancel', [])
|
orders_to_cancel = decision.get('orders_to_cancel', [])
|
||||||
|
|
||||||
if not orders_to_cancel:
|
if not orders_to_cancel:
|
||||||
@ -1501,10 +1502,11 @@ class CryptoAgent:
|
|||||||
logger.warning(f" {trading_type}交易服务未启用")
|
logger.warning(f" {trading_type}交易服务未启用")
|
||||||
return
|
return
|
||||||
|
|
||||||
# 安全检查:验证要取消的订单是否属于当前symbol
|
# 安全检查:验证要取消的订单是否属于当前symbol且方向相反
|
||||||
active_orders = trading_service.get_active_orders()
|
active_orders = trading_service.get_active_orders()
|
||||||
valid_orders = []
|
valid_orders = []
|
||||||
invalid_orders = []
|
invalid_orders = []
|
||||||
|
wrong_direction_orders = []
|
||||||
|
|
||||||
for order_id in orders_to_cancel:
|
for order_id in orders_to_cancel:
|
||||||
# 查找订单
|
# 查找订单
|
||||||
@ -1520,10 +1522,32 @@ class CryptoAgent:
|
|||||||
invalid_orders.append(order_id)
|
invalid_orders.append(order_id)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# 检查订单方向是否与决策相反
|
||||||
|
order_side = order.get('side') # long/short
|
||||||
|
# 决策是buy时应该取消short(做空),决策是sell时应该取消long(做多)
|
||||||
|
should_cancel = False
|
||||||
|
if decision_action == 'buy' and order_side == 'short':
|
||||||
|
should_cancel = True
|
||||||
|
elif decision_action == 'sell' and order_side == 'long':
|
||||||
|
should_cancel = True
|
||||||
|
elif decision_action in ['open_long', 'close_short']:
|
||||||
|
should_cancel = (order_side == 'short')
|
||||||
|
elif decision_action in ['open_short', 'close_long']:
|
||||||
|
should_cancel = (order_side == 'long')
|
||||||
|
|
||||||
|
if not should_cancel:
|
||||||
|
logger.error(f" ❌ 安全拦截:订单 {order_id} 方向为 {order_side},与决策 {decision_action} 同向,不应取消!")
|
||||||
|
wrong_direction_orders.append(order_id)
|
||||||
|
invalid_orders.append(order_id)
|
||||||
|
continue
|
||||||
|
|
||||||
valid_orders.append(order_id)
|
valid_orders.append(order_id)
|
||||||
|
|
||||||
if invalid_orders:
|
if invalid_orders:
|
||||||
logger.error(f" 🚫 拒绝取消 {len(invalid_orders)} 个不属于 {symbol} 的订单")
|
logger.error(f" 🚫 拒绝取消 {len(invalid_orders)} 个不符合条件的订单")
|
||||||
|
|
||||||
|
if wrong_direction_orders:
|
||||||
|
logger.error(f" ⚠️ {len(wrong_direction_orders)} 个同向订单被拦截(不应取消同向订单)")
|
||||||
|
|
||||||
if not valid_orders:
|
if not valid_orders:
|
||||||
logger.warning(f" ⚠️ 没有有效的订单可以取消")
|
logger.warning(f" ⚠️ 没有有效的订单可以取消")
|
||||||
|
|||||||
@ -484,10 +484,26 @@ class TradingDecisionMaker:
|
|||||||
prompt_parts.append(f"\n## 当前挂单(仅 {context['symbol']} 的挂单)")
|
prompt_parts.append(f"\n## 当前挂单(仅 {context['symbol']} 的挂单)")
|
||||||
if pending_orders:
|
if pending_orders:
|
||||||
prompt_parts.append(f"⚠️ 重要:以下挂单都属于当前交易对 {context['symbol']},取消订单时只能选择这些订单ID")
|
prompt_parts.append(f"⚠️ 重要:以下挂单都属于当前交易对 {context['symbol']},取消订单时只能选择这些订单ID")
|
||||||
|
prompt_parts.append(f"⚠️ 取消规则:做空信号时只能取消做多(🟢long)挂单,做多信号时只能取消做空(🔴short)挂单")
|
||||||
|
|
||||||
|
# 分类统计挂单方向
|
||||||
|
long_orders = [o for o in pending_orders if o.get('side') == 'long']
|
||||||
|
short_orders = [o for o in pending_orders if o.get('side') == 'short']
|
||||||
|
|
||||||
|
# 如果只有同向挂单,明确提示LLM
|
||||||
|
signals = context.get('signals', [])
|
||||||
|
if signals:
|
||||||
|
main_action = signals[0].get('action', 'hold') if signals else 'hold'
|
||||||
|
if main_action == 'sell' and not long_orders:
|
||||||
|
prompt_parts.append(f"📌 注意:当前只有做空挂单,与做空信号同向,无需取消!")
|
||||||
|
elif main_action == 'buy' and not short_orders:
|
||||||
|
prompt_parts.append(f"📌 注意:当前只有做多挂单,与做多信号同向,无需取消!")
|
||||||
|
|
||||||
for order in pending_orders:
|
for order in pending_orders:
|
||||||
side_icon = "🟢" if order.get('side') == 'long' else "🔴"
|
side_icon = "🟢" if order.get('side') == 'long' else "🔴"
|
||||||
entry_type = "现价单" if order.get('entry_type') == 'market' else "挂单"
|
entry_type = "现价单" if order.get('entry_type') == 'market' else "挂单"
|
||||||
prompt_parts.append(f"- {side_icon} {order.get('symbol')}: {order.get('side')} | {entry_type}")
|
side_text = "做多" if order.get('side') == 'long' else "做空"
|
||||||
|
prompt_parts.append(f"- {side_icon} {order.get('symbol')}: {side_text}({order.get('side')}) | {entry_type}")
|
||||||
prompt_parts.append(f" 挂单价: ${order.get('entry_price')} | 数量: {order.get('quantity')} USDT")
|
prompt_parts.append(f" 挂单价: ${order.get('entry_price')} | 数量: {order.get('quantity')} USDT")
|
||||||
prompt_parts.append(f" 订单ID: {order.get('order_id')}")
|
prompt_parts.append(f" 订单ID: {order.get('order_id')}")
|
||||||
else:
|
else:
|
||||||
|
|||||||
@ -10,17 +10,31 @@ from app.config import get_settings
|
|||||||
class TelegramService:
|
class TelegramService:
|
||||||
"""Telegram 机器人通知服务"""
|
"""Telegram 机器人通知服务"""
|
||||||
|
|
||||||
def __init__(self, bot_token: str = "", channel_id: str = ""):
|
def __init__(self, bot_token: str = "", channel_id: str = "", service_type: str = "default"):
|
||||||
"""
|
"""
|
||||||
初始化 Telegram 服务
|
初始化 Telegram 服务
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
bot_token: Telegram Bot Token (从 @BotFather 获取)
|
bot_token: Telegram Bot Token (从 @BotFather 获取)
|
||||||
channel_id: 频道 ID (如 @your_channel 或 -1001234567890)
|
channel_id: 频道 ID (如 @your_channel 或 -1001234567890)
|
||||||
|
service_type: 服务类型 (crypto/stock/news/default)
|
||||||
"""
|
"""
|
||||||
settings = get_settings()
|
settings = get_settings()
|
||||||
self.bot_token = bot_token or getattr(settings, 'telegram_bot_token', '')
|
self.bot_token = bot_token or getattr(settings, 'telegram_bot_token', '')
|
||||||
self.channel_id = channel_id or getattr(settings, 'telegram_channel_id', '')
|
self.service_type = service_type
|
||||||
|
|
||||||
|
# 根据服务类型选择频道ID
|
||||||
|
if channel_id:
|
||||||
|
self.channel_id = channel_id
|
||||||
|
else:
|
||||||
|
# 根据service_type选择对应的频道
|
||||||
|
if service_type == "crypto":
|
||||||
|
self.channel_id = getattr(settings, 'telegram_crypto_channel_id', '') or getattr(settings, 'telegram_channel_id', '')
|
||||||
|
elif service_type == "stock":
|
||||||
|
self.channel_id = getattr(settings, 'telegram_stock_channel_id', '') or getattr(settings, 'telegram_channel_id', '')
|
||||||
|
else:
|
||||||
|
self.channel_id = getattr(settings, 'telegram_channel_id', '')
|
||||||
|
|
||||||
# 检查配置开关和必要参数是否都有效
|
# 检查配置开关和必要参数是否都有效
|
||||||
config_enabled = getattr(settings, 'telegram_enabled', True)
|
config_enabled = getattr(settings, 'telegram_enabled', True)
|
||||||
self.enabled = config_enabled and bool(self.bot_token and self.channel_id)
|
self.enabled = config_enabled and bool(self.bot_token and self.channel_id)
|
||||||
@ -30,10 +44,10 @@ class TelegramService:
|
|||||||
logger.info("Telegram 通知已通过配置禁用")
|
logger.info("Telegram 通知已通过配置禁用")
|
||||||
elif self.enabled:
|
elif self.enabled:
|
||||||
self.api_base = f"https://api.telegram.org/bot{self.bot_token}"
|
self.api_base = f"https://api.telegram.org/bot{self.bot_token}"
|
||||||
logger.info(f"Telegram 通知服务初始化完成,频道: {self.channel_id}")
|
logger.info(f"Telegram 通知服务初始化完成 [{service_type}],频道: {self.channel_id}")
|
||||||
else:
|
else:
|
||||||
self.api_base = ""
|
self.api_base = ""
|
||||||
logger.warning("Telegram Bot Token 或 Channel ID 未配置,通知功能已禁用")
|
logger.warning(f"Telegram Bot Token 或 Channel ID 未配置 [{service_type}],通知功能已禁用")
|
||||||
|
|
||||||
async def send_message(self, text: str, parse_mode: str = "HTML") -> bool:
|
async def send_message(self, text: str, parse_mode: str = "HTML") -> bool:
|
||||||
"""
|
"""
|
||||||
@ -245,11 +259,29 @@ class TelegramService:
|
|||||||
|
|
||||||
# 全局实例(延迟初始化)
|
# 全局实例(延迟初始化)
|
||||||
_telegram_service: Optional[TelegramService] = None
|
_telegram_service: Optional[TelegramService] = None
|
||||||
|
_telegram_crypto_service: Optional[TelegramService] = None
|
||||||
|
_telegram_stock_service: Optional[TelegramService] = None
|
||||||
|
|
||||||
|
|
||||||
def get_telegram_service() -> TelegramService:
|
def get_telegram_service() -> TelegramService:
|
||||||
"""获取 Telegram 服务实例"""
|
"""获取 Telegram 服务实例(默认)"""
|
||||||
global _telegram_service
|
global _telegram_service
|
||||||
if _telegram_service is None:
|
if _telegram_service is None:
|
||||||
_telegram_service = TelegramService()
|
_telegram_service = TelegramService()
|
||||||
return _telegram_service
|
return _telegram_service
|
||||||
|
|
||||||
|
|
||||||
|
def get_telegram_crypto_service() -> TelegramService:
|
||||||
|
"""获取加密货币 Telegram 服务实例"""
|
||||||
|
global _telegram_crypto_service
|
||||||
|
if _telegram_crypto_service is None:
|
||||||
|
_telegram_crypto_service = TelegramService(service_type="crypto")
|
||||||
|
return _telegram_crypto_service
|
||||||
|
|
||||||
|
|
||||||
|
def get_telegram_stock_service() -> TelegramService:
|
||||||
|
"""获取股票 Telegram 服务实例"""
|
||||||
|
global _telegram_stock_service
|
||||||
|
if _telegram_stock_service is None:
|
||||||
|
_telegram_stock_service = TelegramService(service_type="stock")
|
||||||
|
return _telegram_stock_service
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user